BluetoothService.java revision cc2c06656ceafbcd91ec5b679aa6c9eae0d9982c
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * TODO: Move this to
19bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly * java/services/com/android/server/BluetoothService.java
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * and make the contructor package private again.
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @hide
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.server;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2730b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganeshimport com.android.internal.app.IBatteryStats;
2830b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
29bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pellyimport android.bluetooth.BluetoothAdapter;
30dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganeshimport android.bluetooth.BluetoothClass;
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.bluetooth.BluetoothDevice;
32f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganeshimport android.bluetooth.BluetoothDeviceProfileState;
335a1e4cf83f5be1b5d79e2643fa791aa269b6a4bcJaikumar Ganeshimport android.bluetooth.BluetoothHeadset;
344ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganeshimport android.bluetooth.BluetoothInputDevice;
356fdd0c6274c81b337ad35b70480f881daf7354c3Danica Changimport android.bluetooth.BluetoothPan;
3696a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganeshimport android.bluetooth.BluetoothProfile;
37f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganeshimport android.bluetooth.BluetoothProfileState;
3824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pellyimport android.bluetooth.BluetoothSocket;
3910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganeshimport android.bluetooth.BluetoothUuid;
40bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pellyimport android.bluetooth.IBluetooth;
4116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pellyimport android.bluetooth.IBluetoothCallback;
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.BroadcastReceiver;
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ContentResolver;
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Intent;
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.IntentFilter;
476e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganeshimport android.content.SharedPreferences;
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Binder;
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Handler;
503fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport android.os.IBinder;
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Message;
523fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport android.os.ParcelUuid;
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.RemoteException;
54105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Projectimport android.os.ServiceManager;
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.Settings;
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log;
57cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganeshimport android.util.Pair;
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
593fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.BufferedInputStream;
603fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.BufferedWriter;
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileDescriptor;
623fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.FileInputStream;
633fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.FileNotFoundException;
643fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.FileWriter;
653fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.IOException;
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.PrintWriter;
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.UnsupportedEncodingException;
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList;
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Arrays;
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.HashMap;
7116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pellyimport java.util.Iterator;
725a1e4cf83f5be1b5d79e2643fa791aa269b6a4bcJaikumar Ganeshimport java.util.List;
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Map;
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
75bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pellypublic class BluetoothService extends IBluetooth.Stub {
76bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    private static final String TAG = "BluetoothService";
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final boolean DBG = true;
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mNativeData;
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private BluetoothEventLoop mEventLoop;
8196a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh    private BluetoothHeadset mBluetoothHeadset;
824ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh    private BluetoothInputDevice mInputDevice;
8374ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh    private BluetoothPan mPan;
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mIsAirplaneSensitive;
8544303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey    private boolean mIsAirplaneToggleable;
86105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private int mBluetoothState;
87997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly    private boolean mRestart = false;  // need to call enable() after disable()
88bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    private boolean mIsDiscovering;
8984690c88f37f395094147d27ace8319a2803a522Jaikumar Ganesh    private int[] mAdapterSdpHandles;
9050b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh    private ParcelUuid[] mAdapterUuids;
91997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly
92bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    private BluetoothAdapter mAdapter;  // constant after init()
939a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    private final BluetoothBondState mBondState;  // local cache of bondings
94105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private final IBatteryStats mBatteryStats;
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final Context mContext;
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
98a8571f15c39da2b7c6e672fef26106f5ac60dea0Jaikumar Ganesh    static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1003fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    private static final String DOCK_ADDRESS_PATH = "/sys/class/switch/dock/bt_addr";
1013fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    private static final String DOCK_PIN_PATH = "/sys/class/switch/dock/bt_pin";
1023fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
1036e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh    private static final String SHARED_PREFERENCE_DOCK_ADDRESS = "dock_bluetooth_address";
1046e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh    private static final String SHARED_PREFERENCES_NAME = "bluetooth_service_settings";
1056e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh
10684690c88f37f395094147d27ace8319a2803a522Jaikumar Ganesh    private static final int MESSAGE_FINISH_DISABLE = 1;
10784690c88f37f395094147d27ace8319a2803a522Jaikumar Ganesh    private static final int MESSAGE_UUID_INTENT = 2;
108fbb238db719cbae98afcb897f509b02edf58b062Jaikumar Ganesh    private static final int MESSAGE_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 3;
109a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh
110a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    // The time (in millisecs) to delay the pairing attempt after the first
111a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    // auto pairing attempt fails. We use an exponential delay with
112a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    // INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY as the initial value and
113a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    // MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY as the max value.
114a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    private static final long INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 3000;
115a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    private static final long MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 12000;
1161caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
1171caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    // The timeout used to sent the UUIDs Intent
1181caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    // This timeout should be greater than the page timeout
1191caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    private static final int UUID_INTENT_DELAY = 6000;
120105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
12116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    /** Always retrieve RFCOMM channel for these SDP UUIDs */
12216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private static final ParcelUuid[] RFCOMM_UUIDS = {
12316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            BluetoothUuid.Handsfree,
12416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            BluetoothUuid.HSP,
12516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            BluetoothUuid.ObexObjectPush };
12616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
1279a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    private final BluetoothAdapterProperties mAdapterProperties;
1289a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    private final BluetoothDeviceProperties mDeviceProperties;
129d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
13016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private final HashMap<String, Map<ParcelUuid, Integer>> mDeviceServiceChannelCache;
13116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private final ArrayList<String> mUuidIntentTracker;
13216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private final HashMap<RemoteService, IBluetoothCallback> mUuidCallbackTracker;
1331caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
13424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private final HashMap<Integer, Integer> mServiceRecordToPid;
13524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
136f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh    private final HashMap<String, BluetoothDeviceProfileState> mDeviceProfileState;
137f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh    private final BluetoothProfileState mA2dpProfileState;
138f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh    private final BluetoothProfileState mHfpProfileState;
1399b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
1409b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    private BluetoothA2dpService mA2dpService;
141cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    private final HashMap<String, Pair<byte[], byte[]>> mDeviceOobData;
142545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh
143a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh    private int mProfilesConnected = 0, mProfilesConnecting = 0, mProfilesDisconnecting = 0;
144707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh
1453fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    private static String mDockAddress;
1463fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    private String mDockPin;
1473fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
148c53cab20b225ba69057441ecb06db6478ab8ff9bJaikumar Ganesh    private int mAdapterConnectionState = BluetoothAdapter.STATE_DISCONNECTED;
149a8571f15c39da2b7c6e672fef26106f5ac60dea0Jaikumar Ganesh    private BluetoothPanProfileHandler mBluetoothPanProfileHandler;
15030b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    private BluetoothInputProfileHandler mBluetoothInputProfileHandler;
151c53cab20b225ba69057441ecb06db6478ab8ff9bJaikumar Ganesh
15216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private static class RemoteService {
15316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        public String address;
15416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        public ParcelUuid uuid;
15516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        public RemoteService(String address, ParcelUuid uuid) {
15616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            this.address = address;
15716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            this.uuid = uuid;
15816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
15916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        @Override
16016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        public boolean equals(Object o) {
16116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (o instanceof RemoteService) {
16216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                RemoteService service = (RemoteService)o;
16316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                return address.equals(service.address) && uuid.equals(service.uuid);
16416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
16516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            return false;
16616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
1675f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root
1685f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root        @Override
1695f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root        public int hashCode() {
1705f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root            int hash = 1;
1715f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root            hash = hash * 31 + (address == null ? 0 : address.hashCode());
1725f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root            hash = hash * 31 + (uuid == null ? 0 : uuid.hashCode());
1735f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root            return hash;
1745f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root        }
17516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    }
17616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static {
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        classInitNative();
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
181bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    public BluetoothService(Context context) {
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext = context;
183105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
184105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Need to do this in place of:
185105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // mBatteryStats = BatteryStatsService.getService();
186105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Since we can not import BatteryStatsService from here. This class really needs to be
187105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // moved to java/services/com/android/server/
188105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo"));
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        initializeNativeDataNative();
191ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project
192ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project        if (isEnabledNative() == 1) {
193ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project            Log.w(TAG, "Bluetooth daemons already running - runtime restart? ");
194ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project            disableNative();
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
196ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project
197de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        mBluetoothState = BluetoothAdapter.STATE_OFF;
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mIsDiscovering = false;
199a8571f15c39da2b7c6e672fef26106f5ac60dea0Jaikumar Ganesh
2009a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        mBondState = new BluetoothBondState(context, this);
2019a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        mAdapterProperties = new BluetoothAdapterProperties(context, this);
2029a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        mDeviceProperties = new BluetoothDeviceProperties(this);
20310eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
20410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        mDeviceServiceChannelCache = new HashMap<String, Map<ParcelUuid, Integer>>();
205cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        mDeviceOobData = new HashMap<String, Pair<byte[], byte[]>>();
2061caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        mUuidIntentTracker = new ArrayList<String>();
20716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        mUuidCallbackTracker = new HashMap<RemoteService, IBluetoothCallback>();
20824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        mServiceRecordToPid = new HashMap<Integer, Integer>();
209f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        mDeviceProfileState = new HashMap<String, BluetoothDeviceProfileState>();
210f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        mA2dpProfileState = new BluetoothProfileState(mContext, BluetoothProfileState.A2DP);
211f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        mHfpProfileState = new BluetoothProfileState(mContext, BluetoothProfileState.HFP);
212f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh
213f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        mHfpProfileState.start();
214f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        mA2dpProfileState.start();
2153fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
2163fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        IntentFilter filter = new IntentFilter();
2176e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh        registerForAirplaneMode(filter);
2186e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh
2193fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        filter.addAction(Intent.ACTION_DOCK_EVENT);
2206e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh        mContext.registerReceiver(mReceiver, filter);
22130b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        mBluetoothInputProfileHandler = BluetoothInputProfileHandler.getInstance(mContext, this);
222a8571f15c39da2b7c6e672fef26106f5ac60dea0Jaikumar Ganesh        mBluetoothPanProfileHandler = BluetoothPanProfileHandler.getInstance(mContext, this);
2233fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    }
2243fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
2259b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public static synchronized String readDockBluetoothAddress() {
2263fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        if (mDockAddress != null) return mDockAddress;
2273fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
2283fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        BufferedInputStream file = null;
2293fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        String dockAddress;
2303fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        try {
2313fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            file = new BufferedInputStream(new FileInputStream(DOCK_ADDRESS_PATH));
2323fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            byte[] address = new byte[17];
2333fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            file.read(address);
2343fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            dockAddress = new String(address);
2353fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            dockAddress = dockAddress.toUpperCase();
2363fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            if (BluetoothAdapter.checkBluetoothAddress(dockAddress)) {
2373fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                mDockAddress = dockAddress;
2383fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                return mDockAddress;
2393fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            } else {
2409a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                Log.e(TAG, "CheckBluetoothAddress failed for car dock address: "
2419a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                        + dockAddress);
2423fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            }
2433fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        } catch (FileNotFoundException e) {
2449a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            Log.e(TAG, "FileNotFoundException while trying to read dock address");
2453fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        } catch (IOException e) {
2469a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            Log.e(TAG, "IOException while trying to read dock address");
2473fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        } finally {
2483fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            if (file != null) {
2493fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                try {
2503fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                    file.close();
2513fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                } catch (IOException e) {
2523fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                    // Ignore
2533fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                }
2543fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            }
2553fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        }
2563fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        mDockAddress = null;
2573fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        return null;
2583fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    }
2593fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
2603fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    private synchronized boolean writeDockPin() {
2613fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        BufferedWriter out = null;
2623fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        try {
2633fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            out = new BufferedWriter(new FileWriter(DOCK_PIN_PATH));
2643fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
2653fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            // Generate a random 4 digit pin between 0000 and 9999
2663fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            // This is not truly random but good enough for our purposes.
2673fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            int pin = (int) Math.floor(Math.random() * 10000);
2683fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
2693fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            mDockPin = String.format("%04d", pin);
2703fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            out.write(mDockPin);
2713fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            return true;
2723fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        } catch (FileNotFoundException e) {
2739a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            Log.e(TAG, "FileNotFoundException while trying to write dock pairing pin");
2743fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        } catch (IOException e) {
2759a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            Log.e(TAG, "IOException while while trying to write dock pairing pin");
2763fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        } finally {
2773fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            if (out != null) {
2783fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                try {
2793fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                    out.close();
2803fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                } catch (IOException e) {
2813fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                    // Ignore
2823fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                }
2833fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            }
2843fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        }
2853fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        mDockPin = null;
2863fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        return false;
2873fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    }
2883fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
2893fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    /*package*/ synchronized String getDockPin() {
2903fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        return mDockPin;
291bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    }
292bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly
293bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    public synchronized void initAfterRegistration() {
294f242b7b931898856bcbcb7ec36cacf43098ba544Nick Pelly        mAdapter = BluetoothAdapter.getDefaultAdapter();
295bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mEventLoop = new BluetoothEventLoop(mContext, mAdapter, this);
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2987d0548d0944e48421857de4aec2822ced325bea0Jaikumar Ganesh    public synchronized void initAfterA2dpRegistration() {
2997d0548d0944e48421857de4aec2822ced325bea0Jaikumar Ganesh        mEventLoop.getProfileProxy();
3007d0548d0944e48421857de4aec2822ced325bea0Jaikumar Ganesh    }
3017d0548d0944e48421857de4aec2822ced325bea0Jaikumar Ganesh
3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void finalize() throws Throwable {
3046e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh        mContext.unregisterReceiver(mReceiver);
3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            cleanupNativeDataNative();
3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super.finalize();
3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean isEnabled() {
3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
3148c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        return isEnabledInternal();
3158c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh    }
3168c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
3178c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh    private boolean isEnabledInternal() {
318de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        return mBluetoothState == BluetoothAdapter.STATE_ON;
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
321105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    public int getBluetoothState() {
322105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
323105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        return mBluetoothState;
324105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    }
325105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
3269a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    int getBluetoothStateInternal() {
3279a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        return mBluetoothState;
3289a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    }
329105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Bring down bluetooth and disable BT in settings. Returns true on success.
3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean disable() {
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return disable(true);
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Bring down bluetooth. Returns true on success.
3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
340e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly     * @param saveSetting If true, persist the new setting
3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean disable(boolean saveSetting) {
343e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission");
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
345105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        switch (mBluetoothState) {
346de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_OFF:
347105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return true;
348de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_ON:
349105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            break;
350105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        default:
351105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return false;
352105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mEnableThread != null && mEnableThread.isAlive()) {
3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
35684690c88f37f395094147d27ace8319a2803a522Jaikumar Ganesh
357de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        setBluetoothState(BluetoothAdapter.STATE_TURNING_OFF);
35884690c88f37f395094147d27ace8319a2803a522Jaikumar Ganesh
35984690c88f37f395094147d27ace8319a2803a522Jaikumar Ganesh        if (mAdapterSdpHandles != null) removeReservedServiceRecordsNative(mAdapterSdpHandles);
36074ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh        setBluetoothTetheringNative(false, BluetoothPanProfileHandler.NAP_ROLE,
36174ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                BluetoothPanProfileHandler.NAP_BRIDGE);
362105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
363105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Allow 3 seconds for profiles to gracefully disconnect
364105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // TODO: Introduce a callback mechanism so that each profile can notify
365bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        // BluetoothService when it is done shutting down
3667a0f816916abb200d9337a5afde5d6d2a637a20aJaikumar Ganesh        disconnectDevices();
3677a0f816916abb200d9337a5afde5d6d2a637a20aJaikumar Ganesh
368105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mHandler.sendMessageDelayed(
369105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                mHandler.obtainMessage(MESSAGE_FINISH_DISABLE, saveSetting ? 1 : 0, 0), 3000);
370105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        return true;
371105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    }
372105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
3737a0f816916abb200d9337a5afde5d6d2a637a20aJaikumar Ganesh    private synchronized void disconnectDevices() {
3747a0f816916abb200d9337a5afde5d6d2a637a20aJaikumar Ganesh        // Disconnect devices handled by BluetoothService.
3757a0f816916abb200d9337a5afde5d6d2a637a20aJaikumar Ganesh        for (BluetoothDevice device: getConnectedInputDevices()) {
3767a0f816916abb200d9337a5afde5d6d2a637a20aJaikumar Ganesh            disconnectInputDevice(device);
3777a0f816916abb200d9337a5afde5d6d2a637a20aJaikumar Ganesh        }
3787a0f816916abb200d9337a5afde5d6d2a637a20aJaikumar Ganesh
3797a0f816916abb200d9337a5afde5d6d2a637a20aJaikumar Ganesh        for (BluetoothDevice device: getConnectedPanDevices()) {
3807a0f816916abb200d9337a5afde5d6d2a637a20aJaikumar Ganesh            disconnectPanDevice(device);
3817a0f816916abb200d9337a5afde5d6d2a637a20aJaikumar Ganesh        }
3827a0f816916abb200d9337a5afde5d6d2a637a20aJaikumar Ganesh    }
383105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
384105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private synchronized void finishDisable(boolean saveSetting) {
385de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        if (mBluetoothState != BluetoothAdapter.STATE_TURNING_OFF) {
386105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return;
3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mEventLoop.stop();
389d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        tearDownNativeDataNative();
3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        disableNative();
3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // mark in progress bondings as cancelled
3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (String address : mBondState.listInState(BluetoothDevice.BOND_BONDING)) {
394005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            mBondState.setBondState(address, BluetoothDevice.BOND_NONE,
3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3982d1fc4e3f5eb612f9ef8a50080310ced1dfaaadfJaikumar Ganesh        // Stop the profile state machine for bonded devices.
3992d1fc4e3f5eb612f9ef8a50080310ced1dfaaadfJaikumar Ganesh        for (String address : mBondState.listInState(BluetoothDevice.BOND_BONDED)) {
4002d1fc4e3f5eb612f9ef8a50080310ced1dfaaadfJaikumar Ganesh            removeProfileState(address);
4012d1fc4e3f5eb612f9ef8a50080310ced1dfaaadfJaikumar Ganesh        }
4022d1fc4e3f5eb612f9ef8a50080310ced1dfaaadfJaikumar Ganesh
4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // update mode
404de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        Intent intent = new Intent(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
405de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        intent.putExtra(BluetoothAdapter.EXTRA_SCAN_MODE, BluetoothAdapter.SCAN_MODE_NONE);
4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.sendBroadcast(intent, BLUETOOTH_PERM);
4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
408105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mIsDiscovering = false;
409bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mAdapterProperties.clear();
41024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        mServiceRecordToPid.clear();
411105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
412a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh        mProfilesConnected = 0;
413a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh        mProfilesConnecting = 0;
414a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh        mProfilesDisconnecting = 0;
415c53cab20b225ba69057441ecb06db6478ab8ff9bJaikumar Ganesh        mAdapterConnectionState = BluetoothAdapter.STATE_DISCONNECTED;
41650b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        mAdapterUuids = null;
41750b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        mAdapterSdpHandles = null;
418a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh
4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (saveSetting) {
4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            persistBluetoothOnSetting(false);
4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
422105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
423de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        setBluetoothState(BluetoothAdapter.STATE_OFF);
424105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
425105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Log bluetooth off to battery stats.
426105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        long ident = Binder.clearCallingIdentity();
427105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        try {
428105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            mBatteryStats.noteBluetoothOff();
429105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        } catch (RemoteException e) {
430105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        } finally {
431105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            Binder.restoreCallingIdentity(ident);
432105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
433997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly
434997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        if (mRestart) {
435997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly            mRestart = false;
436997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly            enable();
437997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        }
4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
440105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    /** Bring up BT and persist BT on in settings */
441105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    public boolean enable() {
442105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        return enable(true);
4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Enable this Bluetooth device, asynchronously.
4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * This turns on/off the underlying hardware.
4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
449105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project     * @param saveSetting If true, persist the new state of BT in settings
450105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project     * @return True on success (so far)
4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
452105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    public synchronized boolean enable(boolean saveSetting) {
4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Airplane mode can prevent Bluetooth radio from being turned on.
45744303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        if (mIsAirplaneSensitive && isAirplaneModeOn() && !mIsAirplaneToggleable) {
4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
460de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        if (mBluetoothState != BluetoothAdapter.STATE_OFF) {
4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mEnableThread != null && mEnableThread.isAlive()) {
4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
466de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        setBluetoothState(BluetoothAdapter.STATE_TURNING_ON);
467105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mEnableThread = new EnableThread(saveSetting);
4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mEnableThread.start();
4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
472997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly    /** Forcibly restart Bluetooth if it is on */
473997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly    /* package */ synchronized void restart() {
474de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        if (mBluetoothState != BluetoothAdapter.STATE_ON) {
475997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly            return;
476997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        }
477997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        mRestart = true;
478997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        if (!disable(false)) {
479997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly            mRestart = false;
480997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        }
481d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
482997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly
483105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private synchronized void setBluetoothState(int state) {
484105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        if (state == mBluetoothState) {
485105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return;
486105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
487105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
4889a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        if (DBG) Log.d(TAG, "Bluetooth state " + mBluetoothState + " -> " + state);
489105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
490de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
491de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, mBluetoothState);
492de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        intent.putExtra(BluetoothAdapter.EXTRA_STATE, state);
493105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
494105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
495105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mBluetoothState = state;
496105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
497105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mContext.sendBroadcast(intent, BLUETOOTH_PERM);
498105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    }
499105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final Handler mHandler = new Handler() {
5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void handleMessage(Message msg) {
5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            switch (msg.what) {
504105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            case MESSAGE_FINISH_DISABLE:
505105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                finishDisable(msg.arg1 != 0);
506105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                break;
5071caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            case MESSAGE_UUID_INTENT:
5081caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh                String address = (String)msg.obj;
50916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (address != null) {
5101caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh                    sendUuidIntent(address);
51116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    makeServiceChannelCallbacks(address);
51216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                }
5131caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh                break;
514a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            case MESSAGE_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY:
515a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                address = (String)msg.obj;
516a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                if (address != null) {
517a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                    createBond(address);
518a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                    return;
519a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                }
520a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                break;
5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private EnableThread mEnableThread;
5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private class EnableThread extends Thread {
5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final boolean mSaveSetting;
529105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        public EnableThread(boolean saveSetting) {
5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mSaveSetting = saveSetting;
5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void run() {
5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean res = (enableNative() == 0);
5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (res) {
535b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                int retryCount = 2;
536b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                boolean running = false;
537b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                while ((retryCount-- > 0) && !running) {
538b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    mEventLoop.start();
5399a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                    // it may take a moment for the other thread to do its
540b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    // thing.  Check periodically for a while.
541b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    int pollCount = 5;
542b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    while ((pollCount-- > 0) && !running) {
543b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                        if (mEventLoop.isEventLoopRunning()) {
544b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                            running = true;
545b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                            break;
546b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                        }
547b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                        try {
548b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                            Thread.sleep(100);
549b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                        } catch (InterruptedException e) {}
550b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    }
551b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                }
552b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                if (!running) {
5539a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                    Log.e(TAG, "bt EnableThread giving up");
554b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    res = false;
555b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    disableNative();
556b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                }
5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (res) {
560d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                if (!setupNativeDataNative()) {
561d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                    return;
562d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                }
5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mSaveSetting) {
5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    persistBluetoothOnSetting(true);
5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
56684690c88f37f395094147d27ace8319a2803a522Jaikumar Ganesh
56784690c88f37f395094147d27ace8319a2803a522Jaikumar Ganesh                mIsDiscovering = false;
56884690c88f37f395094147d27ace8319a2803a522Jaikumar Ganesh                mBondState.readAutoPairingData();
56984690c88f37f395094147d27ace8319a2803a522Jaikumar Ganesh                mBondState.loadBondState();
57084690c88f37f395094147d27ace8319a2803a522Jaikumar Ganesh                initProfileState();
5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5729efb1343a018c479ff57d70e8058658faa8a926dJaikumar Ganesh                // This should be the last step of the the enable thread.
5739efb1343a018c479ff57d70e8058658faa8a926dJaikumar Ganesh                // Because this adds SDP records which asynchronously
5749efb1343a018c479ff57d70e8058658faa8a926dJaikumar Ganesh                // broadcasts the Bluetooth On State in updateBluetoothState.
5759efb1343a018c479ff57d70e8058658faa8a926dJaikumar Ganesh                // So we want all internal state setup before this.
5769efb1343a018c479ff57d70e8058658faa8a926dJaikumar Ganesh                updateSdpRecords();
57750b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh            } else {
57850b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh                setBluetoothState(BluetoothAdapter.STATE_OFF);
5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
580105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            mEnableThread = null;
58150b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        }
58250b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh    }
583105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
58450b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh    private synchronized void addReservedSdpRecords(final ArrayList<ParcelUuid> uuids) {
58550b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        //Register SDP records.
58650b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        int[] svcIdentifiers = new int[uuids.size()];
58750b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        for (int i = 0; i < uuids.size(); i++) {
58850b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh            svcIdentifiers[i] = BluetoothUuid.getServiceIdentifierFromParcelUuid(uuids.get(i));
58950b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        }
59050b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        mAdapterSdpHandles = addReservedServiceRecordsNative(svcIdentifiers);
59150b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh    }
592105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
59350b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh    private synchronized void updateSdpRecords() {
59450b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        ArrayList<ParcelUuid> uuids = new ArrayList<ParcelUuid>();
59550b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh
59650b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        // Add the default records
59750b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        uuids.add(BluetoothUuid.HSP_AG);
59850b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        uuids.add(BluetoothUuid.ObexObjectPush);
59950b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh
60050b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        if (mContext.getResources().
60150b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh                getBoolean(com.android.internal.R.bool.config_voice_capable)) {
60250b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh            uuids.add(BluetoothUuid.Handsfree_AG);
60350b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh            uuids.add(BluetoothUuid.PBAP_PSE);
60450b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        }
60550b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh
60650b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        // Add SDP records for profiles maintained by Android userspace
60750b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        addReservedSdpRecords(uuids);
60850b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh
60950b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        // Enable profiles maintained by Bluez userspace.
61074ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh        setBluetoothTetheringNative(true, BluetoothPanProfileHandler.NAP_ROLE,
61174ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                BluetoothPanProfileHandler.NAP_BRIDGE);
61250b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh
61350b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        // Add SDP records for profiles maintained by Bluez userspace
61450b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        uuids.add(BluetoothUuid.AudioSource);
61550b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        uuids.add(BluetoothUuid.AvrcpTarget);
61650b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        uuids.add(BluetoothUuid.NAP);
61750b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh
61850b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        // Cannot cast uuids.toArray directly since ParcelUuid is parcelable
61950b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        mAdapterUuids = new ParcelUuid[uuids.size()];
62050b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        for (int i = 0; i < uuids.size(); i++) {
62150b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh            mAdapterUuids[i] = uuids.get(i);
62250b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        }
62350b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh    }
62450b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh
6259efb1343a018c479ff57d70e8058658faa8a926dJaikumar Ganesh    /**
6269efb1343a018c479ff57d70e8058658faa8a926dJaikumar Ganesh     * This function is called from Bluetooth Event Loop when onPropertyChanged
6279efb1343a018c479ff57d70e8058658faa8a926dJaikumar Ganesh     * for adapter comes in with UUID property.
6289efb1343a018c479ff57d70e8058658faa8a926dJaikumar Ganesh     * @param uuidsThe uuids of adapter as reported by Bluez.
6299efb1343a018c479ff57d70e8058658faa8a926dJaikumar Ganesh     */
63050b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh    synchronized void updateBluetoothState(String uuids) {
63150b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        if (mBluetoothState == BluetoothAdapter.STATE_TURNING_ON) {
63250b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh            ParcelUuid[] adapterUuids = convertStringToParcelUuid(uuids);
63350b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh
63450b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh            if (mAdapterUuids != null &&
63550b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh                    BluetoothUuid.containsAllUuids(adapterUuids, mAdapterUuids)) {
63650b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh                setBluetoothState(BluetoothAdapter.STATE_ON);
6379a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                autoConnect();
638d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                String[] propVal = {"Pairable", getProperty("Pairable")};
639d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                mEventLoop.onPropertyChanged(propVal);
640b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project
6419efb1343a018c479ff57d70e8058658faa8a926dJaikumar Ganesh                // Log bluetooth on to battery stats.
6429efb1343a018c479ff57d70e8058658faa8a926dJaikumar Ganesh                long ident = Binder.clearCallingIdentity();
6439efb1343a018c479ff57d70e8058658faa8a926dJaikumar Ganesh                try {
6449efb1343a018c479ff57d70e8058658faa8a926dJaikumar Ganesh                    mBatteryStats.noteBluetoothOn();
6459efb1343a018c479ff57d70e8058658faa8a926dJaikumar Ganesh                } catch (RemoteException e) {
6469efb1343a018c479ff57d70e8058658faa8a926dJaikumar Ganesh                } finally {
6479efb1343a018c479ff57d70e8058658faa8a926dJaikumar Ganesh                    Binder.restoreCallingIdentity(ident);
6489efb1343a018c479ff57d70e8058658faa8a926dJaikumar Ganesh                }
6499efb1343a018c479ff57d70e8058658faa8a926dJaikumar Ganesh
65050b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh                if (mIsAirplaneSensitive && isAirplaneModeOn() && !mIsAirplaneToggleable) {
65150b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh                    disable(false);
65250b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh                }
6535c43f735d94a538dc273c8f859d1100a7cdd5c71Daisuke Miyakawa            }
6549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void persistBluetoothOnSetting(boolean bluetoothOn) {
6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long origCallerIdentityToken = Binder.clearCallingIdentity();
6599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.BLUETOOTH_ON,
6609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                bluetoothOn ? 1 : 0);
6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Binder.restoreCallingIdentity(origCallerIdentityToken);
6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
664a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    /*package*/ synchronized boolean attemptAutoPair(String address) {
665a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        if (!mBondState.hasAutoPairingFailed(address) &&
666a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                !mBondState.isAutoPairingBlacklisted(address)) {
667a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            mBondState.attempt(address);
668a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            setPin(address, BluetoothDevice.convertPinToBytes("0000"));
669a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            return true;
670a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        }
671a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        return false;
672a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    }
673a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh
674f487d72215421a02e5a1b2fbff4618bc5ee185cbJaikumar Ganesh    /*package*/ synchronized boolean isFixedPinZerosAutoPairKeyboard(String address) {
675f487d72215421a02e5a1b2fbff4618bc5ee185cbJaikumar Ganesh        // Check for keyboards which have fixed PIN 0000 as the pairing pin
676f487d72215421a02e5a1b2fbff4618bc5ee185cbJaikumar Ganesh        return mBondState.isFixedPinZerosAutoPairKeyboard(address);
677f487d72215421a02e5a1b2fbff4618bc5ee185cbJaikumar Ganesh    }
678f487d72215421a02e5a1b2fbff4618bc5ee185cbJaikumar Ganesh
679a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    /*package*/ synchronized void onCreatePairedDeviceResult(String address, int result) {
680a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        if (result == BluetoothDevice.BOND_SUCCESS) {
681a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            setBondState(address, BluetoothDevice.BOND_BONDED);
682a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            if (mBondState.isAutoPairingAttemptsInProgress(address)) {
683a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                mBondState.clearPinAttempts(address);
684a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            }
685a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        } else if (result == BluetoothDevice.UNBOND_REASON_AUTH_FAILED &&
686a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                mBondState.getAttempt(address) == 1) {
687a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            mBondState.addAutoPairingFailure(address);
688a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            pairingAttempt(address, result);
689a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        } else if (result == BluetoothDevice.UNBOND_REASON_REMOTE_DEVICE_DOWN &&
690a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh              mBondState.isAutoPairingAttemptsInProgress(address)) {
691a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            pairingAttempt(address, result);
692a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        } else {
693a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            setBondState(address, BluetoothDevice.BOND_NONE, result);
694a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            if (mBondState.isAutoPairingAttemptsInProgress(address)) {
695a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                mBondState.clearPinAttempts(address);
696a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            }
697a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        }
698a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    }
699a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh
700a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    /*package*/ synchronized String getPendingOutgoingBonding() {
701a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        return mBondState.getPendingOutgoingBonding();
702a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    }
703a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh
704a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    private void pairingAttempt(String address, int result) {
705a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        // This happens when our initial guess of "0000" as the pass key
706a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        // fails. Try to create the bond again and display the pin dialog
707a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        // to the user. Use back-off while posting the delayed
708a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        // message. The initial value is
709a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        // INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY and the max value is
710a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        // MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY. If the max value is
711a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        // reached, display an error to the user.
712a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        int attempt = mBondState.getAttempt(address);
713a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        if (attempt * INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY >
714a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                    MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY) {
715a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            mBondState.clearPinAttempts(address);
716a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            setBondState(address, BluetoothDevice.BOND_NONE, result);
717a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            return;
718a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        }
719a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh
720a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        Message message = mHandler.obtainMessage(MESSAGE_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY);
721a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        message.obj = address;
722a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        boolean postResult =  mHandler.sendMessageDelayed(message,
723a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                                        attempt * INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY);
724a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        if (!postResult) {
725a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            mBondState.clearPinAttempts(address);
726a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            setBondState(address,
727a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                    BluetoothDevice.BOND_NONE, result);
728a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            return;
729a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        }
730a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        mBondState.attempt(address);
7319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7339a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    /*package*/ BluetoothDevice getRemoteDevice(String address) {
7349a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        return mAdapter.getRemoteDevice(address);
7359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static String toBondStateString(int bondState) {
7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        switch (bondState) {
739005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        case BluetoothDevice.BOND_NONE:
7409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "not bonded";
7419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case BluetoothDevice.BOND_BONDING:
7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "bonding";
7439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case BluetoothDevice.BOND_BONDED:
7449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "bonded";
7459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        default:
7469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "??????";
7479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean setName(String name) {
7519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
7529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (name == null) {
7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
756d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setPropertyString("Name", name);
7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
759d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    //TODO(): setPropertyString, setPropertyInteger, setPropertyBoolean
760d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    // Either have a single property function with Object as the parameter
761d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    // or have a function for each property and then obfuscate in the JNI layer.
762d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    // The following looks dirty.
763d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private boolean setPropertyString(String key, String value) {
7649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
7658c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
766d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setAdapterPropertyStringNative(key, value);
7679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
769d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private boolean setPropertyInteger(String key, int value) {
770d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
7718c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
772d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setAdapterPropertyIntegerNative(key, value);
773d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
7749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
775d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private boolean setPropertyBoolean(String key, boolean value) {
776d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
7778c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
778d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setAdapterPropertyBooleanNative(key, value ? 1 : 0);
7799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
781d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /**
782d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Set the discoverability window for the device.  A timeout of zero
783d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * makes the device permanently discoverable (if the device is
784d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * discoverable).  Setting the timeout to a nonzero value does not make
785d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * a device discoverable; you need to call setMode() to make the device
786d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * explicitly discoverable.
787d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     *
788f51eadaf1f83abfe16a609a4ded6d789494689b2Jake Hamby     * @param timeout The discoverable timeout in seconds.
789d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     */
790d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized boolean setDiscoverableTimeout(int timeout) {
7919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
7929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
793d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setPropertyInteger("DiscoverableTimeout", timeout);
7949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
79612835478ee687a493d1b5882e67b6725bd539c26Nick Pelly    public synchronized boolean setScanMode(int mode, int duration) {
79718b1e79a123b979d25bfa5d0b0ee5d0382dbd64bNick Pelly        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS,
79818b1e79a123b979d25bfa5d0b0ee5d0382dbd64bNick Pelly                                                "Need WRITE_SECURE_SETTINGS permission");
7999a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        boolean pairable;
8009a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        boolean discoverable;
80112835478ee687a493d1b5882e67b6725bd539c26Nick Pelly
802de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        switch (mode) {
803de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.SCAN_MODE_NONE:
804d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            pairable = false;
805d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            discoverable = false;
806de893f550301a60274e87aa8168225e7a7a42184Nick Pelly            break;
807de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
808d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            pairable = true;
809d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            discoverable = false;
810005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            break;
811de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
812d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            pairable = true;
813d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            discoverable = true;
81412835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            if (DBG) Log.d(TAG, "BT Discoverable for " + duration + " seconds");
815005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            break;
816de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        default:
817de893f550301a60274e87aa8168225e7a7a42184Nick Pelly            Log.w(TAG, "Requested invalid scan mode " + mode);
818de893f550301a60274e87aa8168225e7a7a42184Nick Pelly            return false;
819d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
820d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        setPropertyBoolean("Pairable", pairable);
821d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        setPropertyBoolean("Discoverable", discoverable);
8229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
823d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return true;
8249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
826b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh    /*package*/ synchronized String getProperty(String name) {
827b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh        if (!isEnabledInternal()) return null;
8289a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        return mAdapterProperties.getProperty(name);
829b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh    }
830b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh
8319a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    BluetoothAdapterProperties getAdapterProperties() {
8329a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        return mAdapterProperties;
8339a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    }
8349a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
8359a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    BluetoothDeviceProperties getDeviceProperties() {
8369a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        return mDeviceProperties;
8379a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    }
8389a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
8399a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    boolean isRemoteDeviceInCache(String address) {
8409a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        return mDeviceProperties.isInCache(address);
8419a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    }
8429a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
8439a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    void setRemoteDeviceProperty(String address, String name, String value) {
8449a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        mDeviceProperties.setProperty(address, name, value);
8459a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    }
8469a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
8479a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    void updateRemoteDevicePropertiesCache(String address) {
8489a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        mDeviceProperties.updateCache(address);
8499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
851d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized String getAddress() {
852d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
853d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return getProperty("Address");
8549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
856d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized String getName() {
8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
858d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return getProperty("Name");
8599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
86158b93c36409c7fb91a644605f004b6d247d9b540Jaikumar Ganesh    public synchronized ParcelUuid[] getUuids() {
86258b93c36409c7fb91a644605f004b6d247d9b540Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
86358b93c36409c7fb91a644605f004b6d247d9b540Jaikumar Ganesh        String value =  getProperty("UUIDs");
86458b93c36409c7fb91a644605f004b6d247d9b540Jaikumar Ganesh        if (value == null) return null;
86550b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        return convertStringToParcelUuid(value);
86650b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh    }
86758b93c36409c7fb91a644605f004b6d247d9b540Jaikumar Ganesh
86850b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh    private synchronized ParcelUuid[] convertStringToParcelUuid(String value) {
86958b93c36409c7fb91a644605f004b6d247d9b540Jaikumar Ganesh        String[] uuidStrings = null;
87058b93c36409c7fb91a644605f004b6d247d9b540Jaikumar Ganesh        // The UUIDs are stored as a "," separated string.
87158b93c36409c7fb91a644605f004b6d247d9b540Jaikumar Ganesh        uuidStrings = value.split(",");
87258b93c36409c7fb91a644605f004b6d247d9b540Jaikumar Ganesh        ParcelUuid[] uuids = new ParcelUuid[uuidStrings.length];
87358b93c36409c7fb91a644605f004b6d247d9b540Jaikumar Ganesh
87458b93c36409c7fb91a644605f004b6d247d9b540Jaikumar Ganesh        for (int i = 0; i < uuidStrings.length; i++) {
87558b93c36409c7fb91a644605f004b6d247d9b540Jaikumar Ganesh            uuids[i] = ParcelUuid.fromString(uuidStrings[i]);
87658b93c36409c7fb91a644605f004b6d247d9b540Jaikumar Ganesh        }
87758b93c36409c7fb91a644605f004b6d247d9b540Jaikumar Ganesh        return uuids;
87858b93c36409c7fb91a644605f004b6d247d9b540Jaikumar Ganesh    }
87958b93c36409c7fb91a644605f004b6d247d9b540Jaikumar Ganesh
88058b93c36409c7fb91a644605f004b6d247d9b540Jaikumar Ganesh
8819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
882d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Returns the user-friendly name of a remote device.  This value is
883d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * returned from our local cache, which is updated when onPropertyChange
884d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * event is received.
885d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Do not expect to retrieve the updated remote name immediately after
886d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * changing the name on the remote device.
8879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
888d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * @param address Bluetooth address of remote device.
889d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     *
890d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * @return The user-friendly name of the specified remote device.
8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
892d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized String getRemoteName(String address) {
893d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
894005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
895d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return null;
896d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
8979a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        return mDeviceProperties.getProperty(address, "Name");
8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
9019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Get the discoverability window for the device.  A timeout of zero
9029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * means that the device is permanently discoverable (if the device is
9039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * in the discoverable mode).
9049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
9059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The discoverability window of the device, in seconds.  A negative
9069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         value indicates an error.
9079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
9089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized int getDiscoverableTimeout() {
9099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
910d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String timeout = getProperty("DiscoverableTimeout");
911d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (timeout != null)
912d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh           return Integer.valueOf(timeout);
913d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        else
914d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return -1;
9159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized int getScanMode() {
9189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
9198c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal())
920de893f550301a60274e87aa8168225e7a7a42184Nick Pelly            return BluetoothAdapter.SCAN_MODE_NONE;
921d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
922d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        boolean pairable = getProperty("Pairable").equals("true");
923d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        boolean discoverable = getProperty("Discoverable").equals("true");
924d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return bluezStringToScanMode (pairable, discoverable);
9259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
927d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized boolean startDiscovery() {
9289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
9299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
9308c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
9318c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
932d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return startDiscoveryNative();
9339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
935d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized boolean cancelDiscovery() {
9369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
9379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
9388c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
9398c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
940d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return stopDiscoveryNative();
941d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
942d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
943d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized boolean isDiscovering() {
944d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
945d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return mIsDiscovering;
946d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
947d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
948d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ void setIsDiscovering(boolean isDiscovering) {
949d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mIsDiscovering = isDiscovering;
9509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
952cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    private boolean isBondingFeasible(String address) {
9539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
9549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
9558c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
9568c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
957005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
9589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
9599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        address = address.toUpperCase();
9619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9622092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        if (mBondState.getPendingOutgoingBonding() != null) {
9639a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            Log.d(TAG, "Ignoring createBond(): another device is bonding");
9649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // a different device is currently bonding, fail
9659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
9669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Check for bond state only if we are not performing auto
9699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // pairing exponential back-off attempts.
9709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mBondState.isAutoPairingAttemptsInProgress(address) &&
971005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly                mBondState.getBondState(address) != BluetoothDevice.BOND_NONE) {
9729a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            Log.d(TAG, "Ignoring createBond(): this device is already bonding or bonded");
9739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
9749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9763fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        if (address.equals(mDockAddress)) {
9773fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            if (!writeDockPin()) {
9789a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                Log.e(TAG, "Error while writing Pin for the dock");
9793fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                return false;
9803fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            }
9813fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        }
982cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        return true;
983cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    }
9843fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
985cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    public synchronized boolean createBond(String address) {
986cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (!isBondingFeasible(address)) return false;
987cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
988cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (!createPairedDeviceNative(address, 60000  /*1 minute*/ )) {
9899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
9909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9922092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        mBondState.setPendingOutgoingBonding(address);
9939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mBondState.setBondState(address, BluetoothDevice.BOND_BONDING);
9942092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
9959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
9969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
998cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    public synchronized boolean createBondOutOfBand(String address, byte[] hash,
999cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh                                                    byte[] randomizer) {
1000cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (!isBondingFeasible(address)) return false;
10013fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
1002cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (!createPairedDeviceOutOfBandNative(address, 60000 /* 1 minute */)) {
10039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
10049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1006cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        setDeviceOutOfBandData(address, hash, randomizer);
10072092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        mBondState.setPendingOutgoingBonding(address);
10089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mBondState.setBondState(address, BluetoothDevice.BOND_BONDING);
10092092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
10109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
10119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1013cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    public synchronized boolean setDeviceOutOfBandData(String address, byte[] hash,
1014cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh            byte[] randomizer) {
1015cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1016cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh                                                "Need BLUETOOTH_ADMIN permission");
1017cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (!isEnabledInternal()) return false;
1018cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
1019cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        Pair <byte[], byte[]> value = new Pair<byte[], byte[]>(hash, randomizer);
1020cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
1021cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (DBG) {
10229a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            Log.d(TAG, "Setting out of band data for: " + address + ":" +
10239a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                  Arrays.toString(hash) + ":" + Arrays.toString(randomizer));
1024cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        }
1025cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
1026cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        mDeviceOobData.put(address, value);
1027cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        return true;
1028cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    }
1029cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
1030cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    Pair<byte[], byte[]> getDeviceOutOfBandData(BluetoothDevice device) {
1031cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        return mDeviceOobData.get(device.getAddress());
1032cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    }
1033cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
1034cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
1035cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    public synchronized byte[] readOutOfBandData() {
1036cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
1037cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh                                                "Need BLUETOOTH permission");
1038cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (!isEnabledInternal()) return null;
1039cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
1040cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        return readAdapterOutOfBandDataNative();
1041cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    }
1042cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
10439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean cancelBondProcess(String address) {
10449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
10459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
10468c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
10478c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1048005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
10499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
10509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        address = address.toUpperCase();
10529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mBondState.getBondState(address) != BluetoothDevice.BOND_BONDING) {
10539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
10549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1056005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        mBondState.setBondState(address, BluetoothDevice.BOND_NONE,
10579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
1058d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        cancelDeviceCreationNative(address);
10599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
10609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean removeBond(String address) {
10639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
10649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
10658c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
10668c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1067005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
10689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
10699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1070f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
10719b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (state != null) {
1072f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            state.sendMessage(BluetoothDeviceProfileState.UNPAIR);
10739b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            return true;
10749b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        } else {
10759b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            return false;
10769b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
10779b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
10789b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
10799b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public synchronized boolean removeBondInternal(String address) {
1080cc2c06656ceafbcd91ec5b679aa6c9eae0d9982cJaikumar Ganesh        // Unset the trusted device state and then unpair
1081cc2c06656ceafbcd91ec5b679aa6c9eae0d9982cJaikumar Ganesh        setTrust(address, false);
1082d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return removeDeviceNative(getObjectPathFromAddress(address));
10839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized String[] listBonds() {
10869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
10879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mBondState.listInState(BluetoothDevice.BOND_BONDED);
10889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1090a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    /*package*/ synchronized String[] listInState(int state) {
1091a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh      return mBondState.listInState(state);
1092a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    }
1093a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh
10949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized int getBondState(String address) {
10959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1096005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1097b24e11baac589fe16426f2d243b460ab84991c7bNick Pelly            return BluetoothDevice.ERROR;
10989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mBondState.getBondState(address.toUpperCase());
11009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1102a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    /*package*/ synchronized boolean setBondState(String address, int state) {
1103a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        return setBondState(address, state, 0);
1104a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    }
1105a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh
1106a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    /*package*/ synchronized boolean setBondState(String address, int state, int reason) {
1107a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        mBondState.setBondState(address.toUpperCase(), state);
1108a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        return true;
1109a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    }
1110a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh
11113fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    public synchronized boolean isBluetoothDock(String address) {
11126e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh        SharedPreferences sp = mContext.getSharedPreferences(SHARED_PREFERENCES_NAME,
11139a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                Context.MODE_PRIVATE);
11146e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh
11156e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh        return sp.contains(SHARED_PREFERENCE_DOCK_ADDRESS + address);
11163fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    }
11173fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
11189488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh    /*package*/ String[] getRemoteDeviceProperties(String address) {
11198c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return null;
11208c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
11219488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh        String objectPath = getObjectPathFromAddress(address);
11229488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh        return (String [])getDevicePropertiesNative(objectPath);
11239488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh    }
11249488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh
11259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1126efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * Sets the remote device trust state.
1127efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     *
1128efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * @return boolean to indicate operation success or fail
1129efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     */
1130efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    public synchronized boolean setTrust(String address, boolean value) {
1131005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1132e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly            mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1133e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly                    "Need BLUETOOTH_ADMIN permission");
1134efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            return false;
1135efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        }
1136efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue
11378c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
11388c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
11399a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        return setDevicePropertyBooleanNative(
11409a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                getObjectPathFromAddress(address), "Trusted", value ? 1 : 0);
1141efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    }
1142efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue
1143efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    /**
1144efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * Gets the remote device trust state as boolean.
1145efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * Note: this value may be
1146efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * retrieved from cache if we retrieved the data before *
1147efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     *
11489a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * @return boolean to indicate trusted or untrusted state
1149efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     */
1150efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    public synchronized boolean getTrustState(String address) {
1151005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1152efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1153efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            return false;
1154efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        }
1155efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue
11569a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        String val = mDeviceProperties.getProperty(address, "Trusted");
1157efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        if (val == null) {
1158efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            return false;
1159efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        } else {
11609a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            return val.equals("true");
1161efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        }
1162efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    }
1163efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue
1164efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    /**
1165d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Gets the remote major, minor classes encoded as a 32-bit
11669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * integer.
11679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
11689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Note: this value is retrieved from cache, because we get it during
11699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *       remote-device discovery.
11709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
11719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return 32-bit integer encoding the remote major, minor, and service
11729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         classes.
11739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
11749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized int getRemoteClass(String address) {
1175005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1176ea600ccfb7568f60377c4abc85f56c80af7fdbfcNick Pelly            mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1177ea600ccfb7568f60377c4abc85f56c80af7fdbfcNick Pelly            return BluetoothClass.ERROR;
11789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11799a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        String val = mDeviceProperties.getProperty(address, "Class");
1180d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (val == null)
1181d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return BluetoothClass.ERROR;
1182d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        else {
1183d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return Integer.valueOf(val);
1184d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
11859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1186d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
11879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1189dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh     * Gets the UUIDs supported by the remote device
11909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1191dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh     * @return array of 128bit ParcelUuids
11929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1193dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh    public synchronized ParcelUuid[] getRemoteUuids(String address) {
11949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1195005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
11969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return null;
11979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11981caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        return getUuidFromCache(address);
11991caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    }
12001caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
12019a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    ParcelUuid[] getUuidFromCache(String address) {
12029a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        String value = mDeviceProperties.getProperty(address, "UUIDs");
1203dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        if (value == null) return null;
1204dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh
1205dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        String[] uuidStrings = null;
1206d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        // The UUIDs are stored as a "," separated string.
1207dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        uuidStrings = value.split(",");
1208dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        ParcelUuid[] uuids = new ParcelUuid[uuidStrings.length];
1209dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh
1210dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        for (int i = 0; i < uuidStrings.length; i++) {
1211dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh            uuids[i] = ParcelUuid.fromString(uuidStrings[i]);
1212dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        }
1213d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return uuids;
12149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
121616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    /**
121716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * Connect and fetch new UUID's using SDP.
121816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * The UUID's found are broadcast as intents.
121916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * Optionally takes a uuid and callback to fetch the RFCOMM channel for the
122016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * a given uuid.
122116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * TODO: Don't wait UUID_INTENT_DELAY to broadcast UUID intents on success
122216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * TODO: Don't wait UUID_INTENT_DELAY to handle the failure case for
122316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * callback and broadcast intents.
122416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     */
122516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    public synchronized boolean fetchRemoteUuids(String address, ParcelUuid uuid,
122616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            IBluetoothCallback callback) {
12271caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
12288c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
12298c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
12301caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
12311caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            return false;
12321caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        }
12331caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
123416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        RemoteService service = new RemoteService(address, uuid);
123516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        if (uuid != null && mUuidCallbackTracker.get(service) != null) {
123616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            // An SDP query for this address & uuid is already in progress
123716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            // Do not add this callback for the uuid
123816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            return false;
123916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
124016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
12411caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        if (mUuidIntentTracker.contains(address)) {
12421caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            // An SDP query for this address is already in progress
124316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            // Add this uuid onto the in-progress SDP query
124416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (uuid != null) {
124516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                mUuidCallbackTracker.put(new RemoteService(address, uuid), callback);
124616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
12471caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            return true;
12481caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        }
12491caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
12501caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        boolean ret;
12510e09030977aea8b40fd177139528d4b5637c9771Jaikumar Ganesh        // Just do the SDP if the device is already  created and UUIDs are not
12520e09030977aea8b40fd177139528d4b5637c9771Jaikumar Ganesh        // NULL, else create the device and then do SDP.
12539a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        if (mDeviceProperties.isInCache(address) && getRemoteUuids(address) != null) {
12541caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            String path = getObjectPathFromAddress(address);
12551caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            if (path == null) return false;
12561caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
12571caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            // Use an empty string for the UUID pattern
12581caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            ret = discoverServicesNative(path, "");
12591caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        } else {
12601caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            ret = createDeviceNative(address);
12611caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        }
12621caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
12631caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        mUuidIntentTracker.add(address);
126416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        if (uuid != null) {
126516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            mUuidCallbackTracker.put(new RemoteService(address, uuid), callback);
126616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
12671caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
12681caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        Message message = mHandler.obtainMessage(MESSAGE_UUID_INTENT);
12691caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        message.obj = address;
12701caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        mHandler.sendMessageDelayed(message, UUID_INTENT_DELAY);
12711caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        return ret;
12721caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    }
12731caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
12749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1275d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Gets the rfcomm channel associated with the UUID.
127616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * Pulls records from the cache only.
12779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1278d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * @param address Address of the remote device
1279dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh     * @param uuid ParcelUuid of the service attribute
12809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1281d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * @return rfcomm channel associated with the service attribute
128210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh     *         -1 on error
12839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1284dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh    public int getRemoteServiceChannel(String address, ParcelUuid uuid) {
12859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
12868c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return -1;
12878c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1288005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1289b24e11baac589fe16426f2d243b460ab84991c7bNick Pelly            return BluetoothDevice.ERROR;
12909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
129110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        // Check if we are recovering from a crash.
129210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        if (mDeviceProperties.isEmpty()) {
12939a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            if (mDeviceProperties.updateCache(address) == null)
129410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh                return -1;
129510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        }
129610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
129710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        Map<ParcelUuid, Integer> value = mDeviceServiceChannelCache.get(address);
129810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        if (value != null && value.containsKey(uuid))
129910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            return value.get(uuid);
130010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        return -1;
13019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean setPin(String address, byte[] pin) {
13049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
13059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
13068c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
13078c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
13089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (pin == null || pin.length <= 0 || pin.length > 16 ||
1309005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            !BluetoothAdapter.checkBluetoothAddress(address)) {
13109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
13119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        address = address.toUpperCase();
13139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
13149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (data == null) {
13159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.w(TAG, "setPin(" + address + ") called but no native data available, " +
13169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                  "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
13179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                  " or by bluez.\n");
13189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
13199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // bluez API wants pin as a string
13219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String pinString;
13229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
13239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pinString = new String(pin, "UTF8");
13249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (UnsupportedEncodingException uee) {
13259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.e(TAG, "UTF8 not supported?!?");
13269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
13279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return setPinNative(address, pinString, data.intValue());
13299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1331b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    public synchronized boolean setPasskey(String address, int passkey) {
1332b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1333b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                                                "Need BLUETOOTH_ADMIN permission");
13348c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
13358c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1336005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (passkey < 0 || passkey > 999999 || !BluetoothAdapter.checkBluetoothAddress(address)) {
1337b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            return false;
1338b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        }
1339b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        address = address.toUpperCase();
1340b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
1341b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        if (data == null) {
1342b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            Log.w(TAG, "setPasskey(" + address + ") called but no native data available, " +
1343b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                  "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
1344b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                  " or by bluez.\n");
1345b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            return false;
1346b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        }
1347b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        return setPasskeyNative(address, passkey, data.intValue());
1348b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    }
1349b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh
1350b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    public synchronized boolean setPairingConfirmation(String address, boolean confirm) {
1351b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1352b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                                                "Need BLUETOOTH_ADMIN permission");
13538c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
13548c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1355b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        address = address.toUpperCase();
1356b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
1357b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        if (data == null) {
1358b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            Log.w(TAG, "setPasskey(" + address + ") called but no native data available, " +
1359b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                  "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
1360b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                  " or by bluez.\n");
1361b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            return false;
1362b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        }
1363b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        return setPairingConfirmationNative(address, confirm, data.intValue());
1364b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    }
1365b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh
1366cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    public synchronized boolean setRemoteOutOfBandData(String address) {
1367cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1368cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh                                                "Need BLUETOOTH_ADMIN permission");
1369cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (!isEnabledInternal()) return false;
1370cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        address = address.toUpperCase();
1371cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
1372cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (data == null) {
1373cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh            Log.w(TAG, "setRemoteOobData(" + address + ") called but no native data available, " +
1374cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh                  "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
1375cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh                  " or by bluez.\n");
1376cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh            return false;
1377cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        }
1378cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
1379cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        Pair<byte[], byte[]> val = mDeviceOobData.get(address);
1380cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        byte[] hash, randomizer;
1381cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (val == null) {
1382cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh            // TODO: check what should be passed in this case.
1383cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh            hash = new byte[16];
1384cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh            randomizer = new byte[16];
1385cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        } else {
1386cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh            hash = val.first;
1387cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh            randomizer = val.second;
1388cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        }
1389cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        return setRemoteOutOfBandDataNative(address, hash, randomizer, data.intValue());
1390cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    }
1391cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
1392b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    public synchronized boolean cancelPairingUserInput(String address) {
13939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
13949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
13958c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
13968c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1397005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
13989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
13999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1400005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        mBondState.setBondState(address, BluetoothDevice.BOND_NONE,
1401397d8f4f4829a45f4fe7a672cc395466bbc0f442Jaikumar Ganesh                BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
14029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        address = address.toUpperCase();
14039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
14049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (data == null) {
1405b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            Log.w(TAG, "cancelUserInputNative(" + address + ") called but no native data " +
1406b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                "available, ignoring. Maybe the PasskeyAgent Request was already cancelled " +
1407b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                "by the remote or by bluez.\n");
14089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
14099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1410b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        return cancelPairingUserInputNative(address, data.intValue());
14119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14138c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh    /*package*/ void updateDeviceServiceChannelCache(String address) {
14149a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        if (DBG) Log.d(TAG, "updateDeviceServiceChannelCache(" + address + ")");
14159a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
141610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        // We are storing the rfcomm channel numbers only for the uuids
141710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        // we are interested in.
14189a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        ParcelUuid[] deviceUuids = getRemoteUuids(address);
141916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
14209a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        ArrayList<ParcelUuid> applicationUuids = new ArrayList<ParcelUuid>();
142116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
142216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        synchronized (this) {
142316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            for (RemoteService service : mUuidCallbackTracker.keySet()) {
142416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (service.address.equals(address)) {
142516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    applicationUuids.add(service.uuid);
142616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                }
142716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
142816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
142910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
14309a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        Map <ParcelUuid, Integer> uuidToChannelMap = new HashMap<ParcelUuid, Integer>();
143116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
143216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        // Retrieve RFCOMM channel for default uuids
143316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        for (ParcelUuid uuid : RFCOMM_UUIDS) {
143410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            if (BluetoothUuid.isUuidPresent(deviceUuids, uuid)) {
14359a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                int channel = getDeviceServiceChannelForUuid(address, uuid);
14369a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                uuidToChannelMap.put(uuid, channel);
14379a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                if (DBG) Log.d(TAG, "\tuuid(system): " + uuid + " " + channel);
143810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            }
143910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        }
144016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        // Retrieve RFCOMM channel for application requested uuids
144116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        for (ParcelUuid uuid : applicationUuids) {
144216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (BluetoothUuid.isUuidPresent(deviceUuids, uuid)) {
14439a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                int channel = getDeviceServiceChannelForUuid(address, uuid);
14449a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                uuidToChannelMap.put(uuid, channel);
14459a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                if (DBG) Log.d(TAG, "\tuuid(application): " + uuid + " " + channel);
144616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
144716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
144816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
144916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        synchronized (this) {
145016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            // Make application callbacks
145116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            for (Iterator<RemoteService> iter = mUuidCallbackTracker.keySet().iterator();
145216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    iter.hasNext();) {
145316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                RemoteService service = iter.next();
145416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (service.address.equals(address)) {
14559a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                    if (uuidToChannelMap.containsKey(service.uuid)) {
14569a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                        int channel = uuidToChannelMap.get(service.uuid);
14579a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
14589a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                        if (DBG) Log.d(TAG, "Making callback for " + service.uuid +
14599a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                                    " with result " + channel);
146016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        IBluetoothCallback callback = mUuidCallbackTracker.get(service);
146116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        if (callback != null) {
146216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                            try {
146316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                                callback.onRfcommChannelFound(channel);
146416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                            } catch (RemoteException e) {Log.e(TAG, "", e);}
146516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        }
146616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
146716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        iter.remove();
146816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    }
146916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                }
147016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
147116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
147216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            // Update cache
14739a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            mDeviceServiceChannelCache.put(address, uuidToChannelMap);
147416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
147510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh    }
147610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
14779a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    private int getDeviceServiceChannelForUuid(String address,
14789a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            ParcelUuid uuid) {
14799a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        return getDeviceServiceChannelNative(getObjectPathFromAddress(address),
14809a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                uuid.toString(), 0x0004);
14819a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    }
14829a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
148324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    /**
148424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     * b is a handle to a Binder instance, so that this service can be notified
148524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     * for Applications that terminate unexpectedly, to clean there service
148624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     * records
148724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     */
148824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    public synchronized int addRfcommServiceRecord(String serviceName, ParcelUuid uuid,
148924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            int channel, IBinder b) {
14908c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
14918c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return -1;
14928c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
149324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (serviceName == null || uuid == null || channel < 1 ||
149424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                channel > BluetoothSocket.MAX_RFCOMM_CHANNEL) {
149524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            return -1;
149624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
149724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (BluetoothUuid.isUuidPresent(BluetoothUuid.RESERVED_UUIDS, uuid)) {
149824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            Log.w(TAG, "Attempted to register a reserved UUID: " + uuid);
149924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            return -1;
150024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
150124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        int handle = addRfcommServiceRecordNative(serviceName,
150224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                uuid.getUuid().getMostSignificantBits(), uuid.getUuid().getLeastSignificantBits(),
150324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                (short)channel);
15049a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        if (DBG) Log.d(TAG, "new handle " + Integer.toHexString(handle));
150524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (handle == -1) {
150624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            return -1;
150724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
150824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
150924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        int pid = Binder.getCallingPid();
151024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        mServiceRecordToPid.put(new Integer(handle), new Integer(pid));
151124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        try {
151224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            b.linkToDeath(new Reaper(handle, pid), 0);
151324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        } catch (RemoteException e) {}
151424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        return handle;
151524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    }
151624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
151724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    public void removeServiceRecord(int handle) {
151824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
151924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                                                "Need BLUETOOTH permission");
152024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        checkAndRemoveRecord(handle, Binder.getCallingPid());
152124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    }
152224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
152324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private synchronized void checkAndRemoveRecord(int handle, int pid) {
152424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        Integer handleInt = new Integer(handle);
152524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        Integer owner = mServiceRecordToPid.get(handleInt);
152624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (owner != null && pid == owner.intValue()) {
15279a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            if (DBG) Log.d(TAG, "Removing service record " +
15289a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                Integer.toHexString(handle) + " for pid " + pid);
152924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            mServiceRecordToPid.remove(handleInt);
153024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            removeServiceRecordNative(handle);
153124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
153224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    }
153324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
153424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private class Reaper implements IBinder.DeathRecipient {
153524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        int pid;
153624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        int handle;
153724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        Reaper(int handle, int pid) {
153824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            this.pid = pid;
153924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            this.handle = handle;
154024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
154124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        public void binderDied() {
154224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            synchronized (BluetoothService.this) {
15439a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                if (DBG) Log.d(TAG, "Tracked app " + pid + " died");
154424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                checkAndRemoveRecord(handle, pid);
154524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            }
154624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
154724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    }
154824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
15499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
15509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
15519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onReceive(Context context, Intent intent) {
15526e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh            if (intent == null) return;
15536e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh
15549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String action = intent.getAction();
15559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
15569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ContentResolver resolver = context.getContentResolver();
15579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Query the airplane mode from Settings.System just to make sure that
15589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // some random app is not sending this intent and disabling bluetooth
15599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                boolean enabled = !isAirplaneModeOn();
15609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // If bluetooth is currently expected to be on, then enable or disable bluetooth
15619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (Settings.Secure.getInt(resolver, Settings.Secure.BLUETOOTH_ON, 0) > 0) {
15629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (enabled) {
1563105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                        enable(false);
15649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } else {
15659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        disable(false);
15669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
15679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
15686e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh            } else if (Intent.ACTION_DOCK_EVENT.equals(action)) {
15696e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                int state = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
15706e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                        Intent.EXTRA_DOCK_STATE_UNDOCKED);
15716e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                if (DBG) Log.v(TAG, "Received ACTION_DOCK_EVENT with State:" + state);
15726e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                if (state == Intent.EXTRA_DOCK_STATE_UNDOCKED) {
15736e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                    mDockAddress = null;
15746e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                    mDockPin = null;
15756e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                } else {
15766e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                    SharedPreferences.Editor editor =
15776e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                        mContext.getSharedPreferences(SHARED_PREFERENCES_NAME,
15786e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                                mContext.MODE_PRIVATE).edit();
15796e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                    editor.putBoolean(SHARED_PREFERENCE_DOCK_ADDRESS + mDockAddress, true);
158066fce5068a8a3aeb28aaf713843891b286a75280Brad Fitzpatrick                    editor.apply();
15816e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                }
15829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
15839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
15849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
15859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15866e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh    private void registerForAirplaneMode(IntentFilter filter) {
158744303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        final ContentResolver resolver = mContext.getContentResolver();
158844303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        final String airplaneModeRadios = Settings.System.getString(resolver,
15899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Settings.System.AIRPLANE_MODE_RADIOS);
159044303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        final String toggleableRadios = Settings.System.getString(resolver,
159144303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey                Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
159244303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey
159344303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        mIsAirplaneSensitive = airplaneModeRadios == null ? true :
159444303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey                airplaneModeRadios.contains(Settings.System.RADIO_BLUETOOTH);
159544303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        mIsAirplaneToggleable = toggleableRadios == null ? false :
159644303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey                toggleableRadios.contains(Settings.System.RADIO_BLUETOOTH);
159744303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey
15989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mIsAirplaneSensitive) {
15996e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh            filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
16009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
16019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
16029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* Returns true if airplane mode is currently on */
16049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final boolean isAirplaneModeOn() {
16059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return Settings.System.getInt(mContext.getContentResolver(),
16069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Settings.System.AIRPLANE_MODE_ON, 0) == 1;
16079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
16089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16091caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    /* Broadcast the Uuid intent */
16101caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    /*package*/ synchronized void sendUuidIntent(String address) {
16116179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh        ParcelUuid[] uuid = getUuidFromCache(address);
16126179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh        Intent intent = new Intent(BluetoothDevice.ACTION_UUID);
16132d3b98d868cda30535505b2a2fba47aa1c9c052bJaikumar Ganesh        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
16146179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh        intent.putExtra(BluetoothDevice.EXTRA_UUID, uuid);
16156179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh        mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
16169a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        mUuidIntentTracker.remove(address);
161716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    }
161816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
161916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    /*package*/ synchronized void makeServiceChannelCallbacks(String address) {
162016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        for (Iterator<RemoteService> iter = mUuidCallbackTracker.keySet().iterator();
162116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                iter.hasNext();) {
162216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            RemoteService service = iter.next();
162316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (service.address.equals(address)) {
16249a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                if (DBG) Log.d(TAG, "Cleaning up failed UUID channel lookup: "
16259a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                    + service.address + " " + service.uuid);
162616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                IBluetoothCallback callback = mUuidCallbackTracker.get(service);
162716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (callback != null) {
162816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    try {
162916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        callback.onRfcommChannelFound(-1);
163016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    } catch (RemoteException e) {Log.e(TAG, "", e);}
163116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                }
163216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
163316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                iter.remove();
163416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
163516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
16361caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    }
16371caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
16389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
16399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
16409a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        dumpBluetoothState(pw);
16419a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        if (mBluetoothState != BluetoothAdapter.STATE_ON) {
1642105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return;
1643105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
1644105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
164524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("mIsAirplaneSensitive = " + mIsAirplaneSensitive);
164644303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        pw.println("mIsAirplaneToggleable = " + mIsAirplaneToggleable);
164724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
164824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("Local address = " + getAddress());
164924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("Local name = " + getName());
165024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("isDiscovering() = " + isDiscovering());
1651105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
165296a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh        mAdapter.getProfileProxy(mContext,
165396a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh                                 mBluetoothProfileServiceListener, BluetoothProfile.HEADSET);
16544ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh        mAdapter.getProfileProxy(mContext,
16554ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                mBluetoothProfileServiceListener, BluetoothProfile.INPUT_DEVICE);
165674ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh        mAdapter.getProfileProxy(mContext,
165774ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                mBluetoothProfileServiceListener, BluetoothProfile.PAN);
1658105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
16599a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        dumpKnownDevices(pw);
16609a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        dumpAclConnectedDevices(pw);
16619a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        dumpHeadsetService(pw);
16624ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh        dumpInputDeviceProfile(pw);
166374ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh        dumpPanProfile(pw);
16649a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        dumpApplicationServiceRecords(pw);
16654ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh    }
16664ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh
16679a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    private void dumpHeadsetService(PrintWriter pw) {
1668105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        pw.println("\n--Headset Service--");
166996a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh        if (mBluetoothHeadset != null) {
1670bb0773fac888c6748cbf778ab5c99c7d0a2c1309Jaikumar Ganesh            List<BluetoothDevice> deviceList = mBluetoothHeadset.getConnectedDevices();
1671bb0773fac888c6748cbf778ab5c99c7d0a2c1309Jaikumar Ganesh            if (deviceList.size() == 0) {
167274ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                pw.println("No headsets connected");
1673bb0773fac888c6748cbf778ab5c99c7d0a2c1309Jaikumar Ganesh            } else {
1674bb0773fac888c6748cbf778ab5c99c7d0a2c1309Jaikumar Ganesh                BluetoothDevice device = deviceList.get(0);
16759a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                pw.println("\ngetConnectedDevices[0] = " + device);
16769a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                dumpHeadsetConnectionState(pw, device);
1677bb0773fac888c6748cbf778ab5c99c7d0a2c1309Jaikumar Ganesh                pw.println("getBatteryUsageHint() = " +
1678bb0773fac888c6748cbf778ab5c99c7d0a2c1309Jaikumar Ganesh                             mBluetoothHeadset.getBatteryUsageHint(device));
167996a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh            }
168096a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh
16815a1e4cf83f5be1b5d79e2643fa791aa269b6a4bcJaikumar Ganesh            deviceList.clear();
16825a1e4cf83f5be1b5d79e2643fa791aa269b6a4bcJaikumar Ganesh            deviceList = mBluetoothHeadset.getDevicesMatchingConnectionStates(new int[] {
168396a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh                     BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED});
168474ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            pw.println("--Connected and Disconnected Headsets");
1685bb0773fac888c6748cbf778ab5c99c7d0a2c1309Jaikumar Ganesh            for (BluetoothDevice device: deviceList) {
168696a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh                pw.println(device);
168796a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh                if (mBluetoothHeadset.isAudioConnected(device)) {
168896a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh                    pw.println("SCO audio connected to device:" + device);
168996a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh                }
169096a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh            }
1691105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
16924ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh        mAdapter.closeProfileProxy(BluetoothProfile.HEADSET, mBluetoothHeadset);
16934ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh    }
16946c901db72dbaf57d8fdf26adae6721de14ecae22Nick Pelly
16954ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh    private void dumpInputDeviceProfile(PrintWriter pw) {
16964ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh        pw.println("\n--Bluetooth Service- Input Device Profile");
16974ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh        if (mInputDevice != null) {
16984ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            List<BluetoothDevice> deviceList = mInputDevice.getConnectedDevices();
16994ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            if (deviceList.size() == 0) {
170074ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                pw.println("No input devices connected");
17014ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            } else {
170274ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                pw.println("Number of connected devices:" + deviceList.size());
17034ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                BluetoothDevice device = deviceList.get(0);
17044ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                pw.println("getConnectedDevices[0] = " + device);
17054ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                pw.println("Priority of Connected device = " + mInputDevice.getPriority(device));
17064ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh
17074ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                switch (mInputDevice.getConnectionState(device)) {
17084ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                    case BluetoothInputDevice.STATE_CONNECTING:
17094ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                        pw.println("getConnectionState() = STATE_CONNECTING");
17104ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                        break;
17114ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                    case BluetoothInputDevice.STATE_CONNECTED:
17124ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                        pw.println("getConnectionState() = STATE_CONNECTED");
17134ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                        break;
17144ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                    case BluetoothInputDevice.STATE_DISCONNECTING:
17154ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                        pw.println("getConnectionState() = STATE_DISCONNECTING");
17164ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                        break;
17174ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                }
17184ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            }
17194ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            deviceList.clear();
17204ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            deviceList = mInputDevice.getDevicesMatchingConnectionStates(new int[] {
17214ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                     BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED});
17224ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            pw.println("--Connected and Disconnected input devices");
17234ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            for (BluetoothDevice device: deviceList) {
17244ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                pw.println(device);
17254ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            }
172624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
17274ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh        mAdapter.closeProfileProxy(BluetoothProfile.INPUT_DEVICE, mBluetoothHeadset);
17289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
17299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
173074ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh    private void dumpPanProfile(PrintWriter pw) {
173174ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh        pw.println("\n--Bluetooth Service- Pan Profile");
173274ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh        if (mPan != null) {
173374ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            List<BluetoothDevice> deviceList = mPan.getConnectedDevices();
173474ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            if (deviceList.size() == 0) {
173574ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                pw.println("No Pan devices connected");
173674ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            } else {
173774ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                pw.println("Number of connected devices:" + deviceList.size());
173874ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                BluetoothDevice device = deviceList.get(0);
173974ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                pw.println("getConnectedDevices[0] = " + device);
174074ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                pw.println("Priority of Connected device = " + mPan.getPriority(device));
174174ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh
174274ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                switch (mPan.getConnectionState(device)) {
174374ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                    case BluetoothInputDevice.STATE_CONNECTING:
174474ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                        pw.println("getConnectionState() = STATE_CONNECTING");
174574ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                        break;
174674ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                    case BluetoothInputDevice.STATE_CONNECTED:
174774ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                        pw.println("getConnectionState() = STATE_CONNECTED");
174874ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                        break;
174974ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                    case BluetoothInputDevice.STATE_DISCONNECTING:
175074ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                        pw.println("getConnectionState() = STATE_DISCONNECTING");
175174ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                        break;
175274ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                }
175374ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            }
175474ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            deviceList.clear();
175574ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            deviceList = mPan.getDevicesMatchingConnectionStates(new int[] {
175674ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                     BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED});
175774ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            pw.println("--Connected and Disconnected Pan devices");
175874ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            for (BluetoothDevice device: deviceList) {
175974ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                pw.println(device);
176074ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            }
176174ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh        }
17629a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    }
17639a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
17649a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    private void dumpHeadsetConnectionState(PrintWriter pw,
17659a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            BluetoothDevice device) {
17669a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        switch (mBluetoothHeadset.getConnectionState(device)) {
17679a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            case BluetoothHeadset.STATE_CONNECTING:
17689a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                pw.println("getConnectionState() = STATE_CONNECTING");
17699a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                break;
17709a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            case BluetoothHeadset.STATE_CONNECTED:
17719a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                pw.println("getConnectionState() = STATE_CONNECTED");
17729a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                break;
17739a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            case BluetoothHeadset.STATE_DISCONNECTING:
17749a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                pw.println("getConnectionState() = STATE_DISCONNECTING");
17759a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                break;
17769a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            case BluetoothHeadset.STATE_AUDIO_CONNECTED:
17779a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                pw.println("getConnectionState() = STATE_AUDIO_CONNECTED");
17789a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                break;
17799a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        }
17809a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    }
17819a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
17829a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    private void dumpApplicationServiceRecords(PrintWriter pw) {
17839a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        pw.println("\n--Application Service Records--");
17849a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        for (Integer handle : mServiceRecordToPid.keySet()) {
17859a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            Integer pid = mServiceRecordToPid.get(handle);
17869a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            pw.println("\tpid " + pid + " handle " + Integer.toHexString(handle));
17879a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        }
178874ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh        mAdapter.closeProfileProxy(BluetoothProfile.PAN, mBluetoothHeadset);
178974ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh    }
179074ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh
17919a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    private void dumpAclConnectedDevices(PrintWriter pw) {
17929a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        String[] devicesObjectPath = getKnownDevices();
17939a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        pw.println("\n--ACL connected devices--");
17949a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        if (devicesObjectPath != null) {
17959a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            for (String device : devicesObjectPath) {
17969a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                pw.println(getAddressFromObjectPath(device));
17979a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            }
17989a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        }
17999a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    }
18009a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
18019a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    private void dumpKnownDevices(PrintWriter pw) {
18029a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        pw.println("\n--Known devices--");
18039a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        for (String address : mDeviceProperties.keySet()) {
18049a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            int bondState = mBondState.getBondState(address);
18059a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            pw.printf("%s %10s (%d) %s\n", address,
18069a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                       toBondStateString(bondState),
18079a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                       mBondState.getAttempt(address),
18089a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                       getRemoteName(address));
18099a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
18109a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            Map<ParcelUuid, Integer> uuidChannels = mDeviceServiceChannelCache.get(address);
18119a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            if (uuidChannels == null) {
18129a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                pw.println("\tuuids = null");
18139a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            } else {
18149a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                for (ParcelUuid uuid : uuidChannels.keySet()) {
18159a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                    Integer channel = uuidChannels.get(uuid);
18169a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                    if (channel == null) {
18179a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                        pw.println("\t" + uuid);
18189a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                    } else {
18199a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                        pw.println("\t" + uuid + " RFCOMM channel = " + channel);
18209a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                    }
18219a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                }
18229a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            }
18239a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            for (RemoteService service : mUuidCallbackTracker.keySet()) {
18249a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                if (service.address.equals(address)) {
18259a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                    pw.println("\tPENDING CALLBACK: " + service.uuid);
18269a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                }
18279a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            }
18289a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        }
18299a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    }
18309a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
18319a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    private void dumpBluetoothState(PrintWriter pw) {
18329a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        switch(mBluetoothState) {
18339a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        case BluetoothAdapter.STATE_OFF:
18349a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            pw.println("Bluetooth OFF\n");
18359a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            break;
18369a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        case BluetoothAdapter.STATE_TURNING_ON:
18379a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            pw.println("Bluetooth TURNING ON\n");
18389a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            break;
18399a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        case BluetoothAdapter.STATE_TURNING_OFF:
18409a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            pw.println("Bluetooth TURNING OFF\n");
18419a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            break;
18429a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        case BluetoothAdapter.STATE_ON:
18439a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            pw.println("Bluetooth ON\n");
18449a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            break;
18459a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        default:
18469a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            pw.println("Bluetooth UNKNOWN STATE " + mBluetoothState);
18479a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        }
18489a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    }
18499a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
185096a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh    private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
185196a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh        new BluetoothProfile.ServiceListener() {
185296a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh        public void onServiceConnected(int profile, BluetoothProfile proxy) {
18534ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            if (profile == BluetoothProfile.HEADSET) {
18544ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                mBluetoothHeadset = (BluetoothHeadset) proxy;
18554ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            } else if (profile == BluetoothProfile.INPUT_DEVICE) {
18564ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                mInputDevice = (BluetoothInputDevice) proxy;
185774ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            } else if (profile == BluetoothProfile.PAN) {
185874ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                mPan = (BluetoothPan) proxy;
18594ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            }
18604ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh        }
186196a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh        public void onServiceDisconnected(int profile) {
18624ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            if (profile == BluetoothProfile.HEADSET) {
18634ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                mBluetoothHeadset = null;
18644ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            } else if (profile == BluetoothProfile.INPUT_DEVICE) {
18654ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                mInputDevice = null;
186674ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            } else if (profile == BluetoothProfile.PAN) {
186774ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                mPan = null;
18684ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            }
186996a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh        }
187096a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh    };
187196a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh
1872d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ static int bluezStringToScanMode(boolean pairable, boolean discoverable) {
1873d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (pairable && discoverable)
1874bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            return BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE;
1875d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        else if (pairable && !discoverable)
1876bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            return BluetoothAdapter.SCAN_MODE_CONNECTABLE;
1877d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        else
1878bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            return BluetoothAdapter.SCAN_MODE_NONE;
18799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
18809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* package */ static String scanModeToBluezString(int mode) {
18829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        switch (mode) {
1883bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        case BluetoothAdapter.SCAN_MODE_NONE:
18849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "off";
1885bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
18869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "connectable";
1887bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
18889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "discoverable";
18899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
18909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return null;
18919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
18929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1893d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /*package*/ String getAddressFromObjectPath(String objectPath) {
18949a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        String adapterObjectPath = mAdapterProperties.getObjectPath();
1895d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (adapterObjectPath == null || objectPath == null) {
1896f51eadaf1f83abfe16a609a4ded6d789494689b2Jake Hamby            Log.e(TAG, "getAddressFromObjectPath: AdapterObjectPath:" + adapterObjectPath +
1897d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                    "  or deviceObjectPath:" + objectPath + " is null");
1898d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return null;
1899d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
1900d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (!objectPath.startsWith(adapterObjectPath)) {
1901f51eadaf1f83abfe16a609a4ded6d789494689b2Jake Hamby            Log.e(TAG, "getAddressFromObjectPath: AdapterObjectPath:" + adapterObjectPath +
1902d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                    "  is not a prefix of deviceObjectPath:" + objectPath +
1903d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                    "bluetoothd crashed ?");
1904d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return null;
1905d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
1906d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String address = objectPath.substring(adapterObjectPath.length());
1907d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (address != null) return address.replace('_', ':');
1908d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1909d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        Log.e(TAG, "getAddressFromObjectPath: Address being returned is null");
1910d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return null;
1911d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
1912d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1913d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /*package*/ String getObjectPathFromAddress(String address) {
19149a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        String path = mAdapterProperties.getObjectPath();
1915d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (path == null) {
1916d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            Log.e(TAG, "Error: Object Path is null");
1917d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return null;
1918d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
1919d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        path = path + address.replace(":", "_");
1920d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return path;
1921d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
1922d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1923b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh    /*package */ void setLinkTimeout(String address, int num_slots) {
1924b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh        String path = getObjectPathFromAddress(address);
1925b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh        boolean result = setLinkTimeoutNative(path, num_slots);
1926b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh
19279a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        if (!result) Log.d(TAG, "Set Link Timeout to " + num_slots + " slots failed");
1928b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh    }
1929b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh
193030b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    /**** Handlers for PAN  Profile ****/
193130b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
193230b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    public synchronized boolean isTetheringOn() {
193330b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
193430b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        return mBluetoothPanProfileHandler.isTetheringOn();
193530b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
193630b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
193730b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    /*package*/ synchronized boolean allowIncomingTethering() {
193830b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        return mBluetoothPanProfileHandler.allowIncomingTethering();
193930b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
194030b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
194130b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    public synchronized void setBluetoothTethering(boolean value) {
194230b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
194330b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        mBluetoothPanProfileHandler.setBluetoothTethering(value);
194430b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
194530b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
194674ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh    public synchronized int getPanDeviceConnectionState(BluetoothDevice device) {
194730b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
194874ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh        return mBluetoothPanProfileHandler.getPanDeviceConnectionState(device);
194930b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
195030b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
195130b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    public synchronized boolean connectPanDevice(BluetoothDevice device) {
195230b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
195330b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh            "Need BLUETOOTH_ADMIN permission");
195430b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        return mBluetoothPanProfileHandler.connectPanDevice(device);
195530b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
195630b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
195730b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    public synchronized List<BluetoothDevice> getConnectedPanDevices() {
195830b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
195930b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        return mBluetoothPanProfileHandler.getConnectedPanDevices();
196030b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
196130b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
196274ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh    public synchronized List<BluetoothDevice> getPanDevicesMatchingConnectionStates(
196374ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            int[] states) {
196474ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
196574ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh        return mBluetoothPanProfileHandler.getPanDevicesMatchingConnectionStates(states);
196674ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh    }
196774ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh
196830b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    public synchronized boolean disconnectPanDevice(BluetoothDevice device) {
196930b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
197030b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh            "Need BLUETOOTH_ADMIN permission");
197130b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        return mBluetoothPanProfileHandler.disconnectPanDevice(device);
197230b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
197330b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
197430b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    /*package*/ synchronized void handlePanDeviceStateChange(BluetoothDevice device,
197530b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh                                                             String iface,
197630b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh                                                             int state,
197730b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh                                                             int role) {
197830b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        mBluetoothPanProfileHandler.handlePanDeviceStateChange(device, iface, state, role);
197930b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
198030b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
198130b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    /*package*/ synchronized void handlePanDeviceStateChange(BluetoothDevice device,
198230b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh                                                             int state, int role) {
198330b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        mBluetoothPanProfileHandler.handlePanDeviceStateChange(device, null, state, role);
198430b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
198530b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
198630b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    /**** Handlers for Input Device Profile ****/
198730b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
198830b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    public synchronized boolean connectInputDevice(BluetoothDevice device) {
198930b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
199030b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh                                                "Need BLUETOOTH_ADMIN permission");
199130b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        BluetoothDeviceProfileState state = mDeviceProfileState.get(device.getAddress());
199230b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        return mBluetoothInputProfileHandler.connectInputDevice(device, state);
199330b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
199430b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
199530b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    public synchronized boolean connectInputDeviceInternal(BluetoothDevice device) {
199630b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        return mBluetoothInputProfileHandler.connectInputDeviceInternal(device);
199730b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
199830b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
199930b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    public synchronized boolean disconnectInputDevice(BluetoothDevice device) {
200030b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
200130b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh                                                "Need BLUETOOTH_ADMIN permission");
200230b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        BluetoothDeviceProfileState state = mDeviceProfileState.get(device.getAddress());
200330b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        return mBluetoothInputProfileHandler.disconnectInputDevice(device, state);
200430b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
200530b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
200630b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    public synchronized boolean disconnectInputDeviceInternal(BluetoothDevice device) {
200730b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        return mBluetoothInputProfileHandler.disconnectInputDeviceInternal(device);
200830b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
200930b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
20104ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh    public synchronized int getInputDeviceConnectionState(BluetoothDevice device) {
201130b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
20124ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh        return mBluetoothInputProfileHandler.getInputDeviceConnectionState(device);
201330b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
201430b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
201530b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
201630b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    public synchronized List<BluetoothDevice> getConnectedInputDevices() {
201730b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
201830b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        return mBluetoothInputProfileHandler.getConnectedInputDevices();
201930b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
202030b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
20214ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh    public synchronized List<BluetoothDevice> getInputDevicesMatchingConnectionStates(
20224ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            int[] states) {
20234ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
20244ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh        return mBluetoothInputProfileHandler.getInputDevicesMatchingConnectionStates(states);
20254ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh    }
20264ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh
20274ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh
202830b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    public synchronized int getInputDevicePriority(BluetoothDevice device) {
202930b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
203030b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        return mBluetoothInputProfileHandler.getInputDevicePriority(device);
203130b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
203230b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
203330b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    public synchronized boolean setInputDevicePriority(BluetoothDevice device, int priority) {
203430b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
203530b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh                                                "Need BLUETOOTH_ADMIN permission");
203630b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        return mBluetoothInputProfileHandler.setInputDevicePriority(device, priority);
203730b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
203830b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
203930b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    /*package*/synchronized List<BluetoothDevice> lookupInputDevicesMatchingStates(int[] states) {
204030b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        return mBluetoothInputProfileHandler.lookupInputDevicesMatchingStates(states);
204130b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
204230b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
204330b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    /*package*/ synchronized void handleInputDevicePropertyChange(String address, boolean connected) {
204430b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        mBluetoothInputProfileHandler.handleInputDevicePropertyChange(address, connected);
204530b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
204630b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
20479b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public boolean connectHeadset(String address) {
204896a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh        if (getBondState(address) != BluetoothDevice.BOND_BONDED) return false;
204996a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh
2050f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
20519b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (state != null) {
2052f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            Message msg = new Message();
2053f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.arg1 = BluetoothDeviceProfileState.CONNECT_HFP_OUTGOING;
2054f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.obj = state;
2055f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            mHfpProfileState.sendMessage(msg);
2056f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            return true;
20579b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
20589b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        return false;
20599b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
20609b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
20619b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public boolean disconnectHeadset(String address) {
206296a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh        if (getBondState(address) != BluetoothDevice.BOND_BONDED) return false;
206396a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh
2064f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
20659b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (state != null) {
2066f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            Message msg = new Message();
2067f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.arg1 = BluetoothDeviceProfileState.DISCONNECT_HFP_OUTGOING;
2068f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.obj = state;
2069f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            mHfpProfileState.sendMessage(msg);
20709b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            return true;
20719b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
20729b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        return false;
20739b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
20749b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
20759b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public boolean connectSink(String address) {
207696a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh        if (getBondState(address) != BluetoothDevice.BOND_BONDED) return false;
207796a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh
2078f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
20799b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (state != null) {
2080f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            Message msg = new Message();
2081f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.arg1 = BluetoothDeviceProfileState.CONNECT_A2DP_OUTGOING;
2082f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.obj = state;
2083f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            mA2dpProfileState.sendMessage(msg);
2084f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            return true;
20859b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
20869b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        return false;
20879b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
20889b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
20899b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public boolean disconnectSink(String address) {
209096a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh        if (getBondState(address) != BluetoothDevice.BOND_BONDED) return false;
209196a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh
2092f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
20939b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (state != null) {
2094f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            Message msg = new Message();
2095f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.arg1 = BluetoothDeviceProfileState.DISCONNECT_A2DP_OUTGOING;
2096f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.obj = state;
2097f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            mA2dpProfileState.sendMessage(msg);
20989b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            return true;
20999b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
21009b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        return false;
21019b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
21029b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
21039a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    BluetoothDeviceProfileState addProfileState(String address) {
2104f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
21059b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (state != null) return state;
21069b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
2107f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        state = new BluetoothDeviceProfileState(mContext, address, this, mA2dpService);
2108f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        mDeviceProfileState.put(address, state);
21099b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        state.start();
21109b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        return state;
21119b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
21129b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
21139a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    void removeProfileState(String address) {
2114f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        mDeviceProfileState.remove(address);
21159b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
21169b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
21179a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    synchronized String[] getKnownDevices() {
21189a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        String[] bonds = null;
21199a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        String val = getProperty("Devices");
21209a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        if (val != null) {
21219a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            bonds = val.split(",");
21229a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        }
21239a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        return bonds;
21249a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    }
21259a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
21269b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    private void initProfileState() {
21279a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        String[] bonds = null;
21289a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        String val = mAdapterProperties.getProperty("Devices");
21299b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (val != null) {
21309b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            bonds = val.split(",");
21319b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
21329b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (bonds == null) {
21339b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            return;
21349b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
21359b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        for (String path : bonds) {
21369b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            String address = getAddressFromObjectPath(path);
2137f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            BluetoothDeviceProfileState state = addProfileState(address);
21389a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        }
21399a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    }
21409a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
21419a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    private void autoConnect() {
21429a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        String[] bonds = getKnownDevices();
21439a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        if (bonds == null) {
21449a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            return;
21459a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        }
21469a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        for (String path : bonds) {
21479a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            String address = getAddressFromObjectPath(path);
21489a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
21499a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            if (state != null) {
21509a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                Message msg = new Message();
21519a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                msg.what = BluetoothDeviceProfileState.AUTO_CONNECT_PROFILES;
21529a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                state.sendMessage(msg);
21539a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            }
21549b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
21559b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
21569b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
21579b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public boolean notifyIncomingConnection(String address) {
2158f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        BluetoothDeviceProfileState state =
2159f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh             mDeviceProfileState.get(address);
21609b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (state != null) {
21619b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            Message msg = new Message();
2162f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.what = BluetoothDeviceProfileState.CONNECT_HFP_INCOMING;
21639b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            state.sendMessage(msg);
21649b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            return true;
21659b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
21669b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        return false;
21679b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
21689b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
21699b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    /*package*/ boolean notifyIncomingA2dpConnection(String address) {
2170f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh       BluetoothDeviceProfileState state =
2171f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            mDeviceProfileState.get(address);
21729b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh       if (state != null) {
21739b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh           Message msg = new Message();
2174f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh           msg.what = BluetoothDeviceProfileState.CONNECT_A2DP_INCOMING;
21759b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh           state.sendMessage(msg);
21769b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh           return true;
21779b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh       }
21789b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh       return false;
21799b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
21809b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
21819b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    /*package*/ void setA2dpService(BluetoothA2dpService a2dpService) {
21829b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        mA2dpService = a2dpService;
21839b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
21849b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
218570a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh    public void sendProfileStateMessage(int profile, int cmd) {
218670a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh        Message msg = new Message();
218770a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh        msg.what = cmd;
218870a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh        if (profile == BluetoothProfileState.HFP) {
218970a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh            mHfpProfileState.sendMessage(msg);
219070a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh        } else if (profile == BluetoothProfileState.A2DP) {
219170a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh            mA2dpProfileState.sendMessage(msg);
219270a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh        }
219370a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh    }
219470a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh
2195c53cab20b225ba69057441ecb06db6478ab8ff9bJaikumar Ganesh    public int getAdapterConnectionState() {
2196c53cab20b225ba69057441ecb06db6478ab8ff9bJaikumar Ganesh        return mAdapterConnectionState;
2197c53cab20b225ba69057441ecb06db6478ab8ff9bJaikumar Ganesh    }
2198c53cab20b225ba69057441ecb06db6478ab8ff9bJaikumar Ganesh
2199a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh    public synchronized void sendConnectionStateChange(BluetoothDevice device, int state,
2200a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh                                                        int prevState) {
22019a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        // Since this is a binder call check if Bluetooth is on still
22029a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        if (mBluetoothState == BluetoothAdapter.STATE_OFF) return;
22039a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
22049a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        if (updateCountersAndCheckForConnectionStateChange(state, prevState)) {
22059a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            if (!validateProfileConnectionState(state) ||
22069a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                    !validateProfileConnectionState(prevState)) {
22079a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                // Previously, an invalid state was broadcast anyway,
22089a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                // with the invalid state converted to -1 in the intent.
22099a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                // Better to log an error and not send an intent with
22109a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                // invalid contents or set mAdapterConnectionState to -1.
22119a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                Log.e(TAG, "Error in sendConnectionStateChange: "
22129a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                        + "prevState " + prevState + " state " + state);
22139a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                return;
22149a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            }
2215c53cab20b225ba69057441ecb06db6478ab8ff9bJaikumar Ganesh
2216c53cab20b225ba69057441ecb06db6478ab8ff9bJaikumar Ganesh            mAdapterConnectionState = state;
2217c53cab20b225ba69057441ecb06db6478ab8ff9bJaikumar Ganesh
2218a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh            Intent intent = new Intent(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
2219a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh            intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
22209a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            intent.putExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE,
22219a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                    convertToAdapterState(state));
22229a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_CONNECTION_STATE,
22239a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                    convertToAdapterState(prevState));
2224a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh            mContext.sendBroadcast(intent, BLUETOOTH_PERM);
22259a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            Log.d(TAG, "CONNECTION_STATE_CHANGE: " + device + ": "
22269a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                    + prevState + " -> " + state);
2227a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh        }
2228a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh    }
2229a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh
22309a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    private boolean validateProfileConnectionState(int state) {
22319a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        return (state == BluetoothProfile.STATE_DISCONNECTED ||
22329a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                state == BluetoothProfile.STATE_CONNECTING ||
22339a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                state == BluetoothProfile.STATE_CONNECTED ||
22349a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                state == BluetoothProfile.STATE_DISCONNECTING);
22359a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    }
22369a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
22379a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    private int convertToAdapterState(int state) {
2238a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh        switch (state) {
22399a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            case BluetoothProfile.STATE_DISCONNECTED:
22409a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                return BluetoothAdapter.STATE_DISCONNECTED;
22419a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            case BluetoothProfile.STATE_DISCONNECTING:
22429a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                return BluetoothAdapter.STATE_DISCONNECTING;
22439a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            case BluetoothProfile.STATE_CONNECTED:
22449a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                return BluetoothAdapter.STATE_CONNECTED;
2245a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh            case BluetoothProfile.STATE_CONNECTING:
2246a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh                return BluetoothAdapter.STATE_CONNECTING;
22479a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        }
22489a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        Log.e(TAG, "Error in convertToAdapterState");
22499a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        return -1;
22509a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    }
22519a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
22529a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    private boolean updateCountersAndCheckForConnectionStateChange(int state, int prevState) {
22539a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        switch (prevState) {
22549a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            case BluetoothProfile.STATE_CONNECTING:
22559a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                mProfilesConnecting--;
22569a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                break;
22579a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
2258a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh            case BluetoothProfile.STATE_CONNECTED:
22599a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                mProfilesConnected--;
22609a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                break;
22619a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
2262a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh            case BluetoothProfile.STATE_DISCONNECTING:
22639a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                mProfilesDisconnecting--;
22649a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                break;
2265a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh        }
2266a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh
2267a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh        switch (state) {
2268a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh            case BluetoothProfile.STATE_CONNECTING:
2269a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh                mProfilesConnecting++;
22709a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                return (mProfilesConnected == 0 && mProfilesConnecting == 1);
2271a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh
2272a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh            case BluetoothProfile.STATE_CONNECTED:
2273a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh                mProfilesConnected++;
22749a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                return (mProfilesConnected == 1);
2275a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh
2276a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh            case BluetoothProfile.STATE_DISCONNECTING:
2277a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh                mProfilesDisconnecting++;
22789a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                return (mProfilesConnected == 0 && mProfilesDisconnecting == 1);
2279a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh
2280a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh            case BluetoothProfile.STATE_DISCONNECTED:
22819a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                return (mProfilesConnected == 0 && mProfilesConnecting == 0);
2282a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh
22839a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            default:
22849a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                return true;
2285a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh        }
22869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2287d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
2288d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native static void classInitNative();
2289d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native void initializeNativeDataNative();
2290d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setupNativeDataNative();
2291d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean tearDownNativeDataNative();
2292d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native void cleanupNativeDataNative();
22939a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    /*package*/ native String getAdapterPathNative();
2294d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
2295d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native int isEnabledNative();
2296d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native int enableNative();
2297d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native int disableNative();
2298d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
22999a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    /*package*/ native Object[] getAdapterPropertiesNative();
2300d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native Object[] getDevicePropertiesNative(String objectPath);
2301d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setAdapterPropertyStringNative(String key, String value);
2302d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setAdapterPropertyIntegerNative(String key, int value);
2303d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setAdapterPropertyBooleanNative(String key, int value);
2304d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
2305d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean startDiscoveryNative();
2306d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean stopDiscoveryNative();
2307d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
2308d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean createPairedDeviceNative(String address, int timeout_ms);
2309cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    private native boolean createPairedDeviceOutOfBandNative(String address, int timeout_ms);
2310cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    private native byte[] readAdapterOutOfBandDataNative();
2311cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
2312d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean cancelDeviceCreationNative(String address);
2313d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean removeDeviceNative(String objectPath);
2314d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native int getDeviceServiceChannelNative(String objectPath, String uuid,
2315d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            int attributeId);
2316d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
2317b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    private native boolean cancelPairingUserInputNative(String address, int nativeData);
2318d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setPinNative(String address, String pin, int nativeData);
2319b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    private native boolean setPasskeyNative(String address, int passkey, int nativeData);
2320b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    private native boolean setPairingConfirmationNative(String address, boolean confirm,
2321b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            int nativeData);
2322cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    private native boolean setRemoteOutOfBandDataNative(String address, byte[] hash,
2323cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh                                                        byte[] randomizer, int nativeData);
2324cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
232524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private native boolean setDevicePropertyBooleanNative(String objectPath, String key,
232624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            int value);
23271caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    private native boolean createDeviceNative(String address);
232816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    /*package*/ native boolean discoverServicesNative(String objectPath, String pattern);
232910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
233024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private native int addRfcommServiceRecordNative(String name, long uuidMsb, long uuidLsb,
233124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            short channel);
233224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private native boolean removeServiceRecordNative(int handle);
2333b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh    private native boolean setLinkTimeoutNative(String path, int num_slots);
233430b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    native boolean connectInputDeviceNative(String path);
233530b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    native boolean disconnectInputDeviceNative(String path);
23366fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang
2337a8571f15c39da2b7c6e672fef26106f5ac60dea0Jaikumar Ganesh    native boolean setBluetoothTetheringNative(boolean value, String nap, String bridge);
2338a8571f15c39da2b7c6e672fef26106f5ac60dea0Jaikumar Ganesh    native boolean connectPanDeviceNative(String path, String dstRole);
2339a8571f15c39da2b7c6e672fef26106f5ac60dea0Jaikumar Ganesh    native boolean disconnectPanDeviceNative(String path);
2340a8571f15c39da2b7c6e672fef26106f5ac60dea0Jaikumar Ganesh    native boolean disconnectPanServerDeviceNative(String path,
2341a44a1e77ef435942b2ff60e9e60d3a64b43d775bJaikumar Ganesh            String address, String iface);
234284690c88f37f395094147d27ace8319a2803a522Jaikumar Ganesh
234384690c88f37f395094147d27ace8319a2803a522Jaikumar Ganesh    private native int[] addReservedServiceRecordsNative(int[] uuuids);
234484690c88f37f395094147d27ace8319a2803a522Jaikumar Ganesh    private native boolean removeReservedServiceRecordsNative(int[] handles);
23459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
2346