BluetoothService.java revision 8adcacbf83697d1299812f5365380b097898567a
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
27bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pellyimport android.bluetooth.BluetoothAdapter;
28dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganeshimport android.bluetooth.BluetoothClass;
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.bluetooth.BluetoothDevice;
30f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganeshimport android.bluetooth.BluetoothDeviceProfileState;
315a1e4cf83f5be1b5d79e2643fa791aa269b6a4bcJaikumar Ganeshimport android.bluetooth.BluetoothHeadset;
322ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganeshimport android.bluetooth.BluetoothHealthAppConfiguration;
334ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganeshimport android.bluetooth.BluetoothInputDevice;
346fdd0c6274c81b337ad35b70480f881daf7354c3Danica Changimport android.bluetooth.BluetoothPan;
3596a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganeshimport android.bluetooth.BluetoothProfile;
36f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganeshimport android.bluetooth.BluetoothProfileState;
3724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pellyimport android.bluetooth.BluetoothSocket;
3810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganeshimport android.bluetooth.BluetoothUuid;
39bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pellyimport android.bluetooth.IBluetooth;
4016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pellyimport android.bluetooth.IBluetoothCallback;
41fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganeshimport android.bluetooth.IBluetoothHealthCallback;
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;
522ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganeshimport android.os.ParcelFileDescriptor;
533fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport android.os.ParcelUuid;
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.RemoteException;
55105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Projectimport android.os.ServiceManager;
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.Settings;
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log;
58cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganeshimport android.util.Pair;
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
60fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganeshimport com.android.internal.app.IBatteryStats;
61fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh
623fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.BufferedInputStream;
63a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xieimport java.io.BufferedReader;
643fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.BufferedWriter;
65a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xieimport java.io.DataInputStream;
66a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xieimport java.io.File;
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileDescriptor;
683fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.FileInputStream;
693fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.FileNotFoundException;
703fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.FileWriter;
71a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xieimport java.io.InputStreamReader;
723fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.IOException;
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.PrintWriter;
74a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xieimport java.io.RandomAccessFile;
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.UnsupportedEncodingException;
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList;
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Arrays;
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.HashMap;
7916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pellyimport java.util.Iterator;
805a1e4cf83f5be1b5d79e2643fa791aa269b6a4bcJaikumar Ganeshimport java.util.List;
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Map;
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
83bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pellypublic class BluetoothService extends IBluetooth.Stub {
84bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    private static final String TAG = "BluetoothService";
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final boolean DBG = true;
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mNativeData;
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private BluetoothEventLoop mEventLoop;
8996a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh    private BluetoothHeadset mBluetoothHeadset;
904ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh    private BluetoothInputDevice mInputDevice;
9174ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh    private BluetoothPan mPan;
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mIsAirplaneSensitive;
9344303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey    private boolean mIsAirplaneToggleable;
94105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private int mBluetoothState;
95997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly    private boolean mRestart = false;  // need to call enable() after disable()
96bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    private boolean mIsDiscovering;
9784690c88f37f395094147d27ace8319a2803a522Jaikumar Ganesh    private int[] mAdapterSdpHandles;
9850b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh    private ParcelUuid[] mAdapterUuids;
99997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly
100bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    private BluetoothAdapter mAdapter;  // constant after init()
1019a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    private final BluetoothBondState mBondState;  // local cache of bondings
102105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private final IBatteryStats mBatteryStats;
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final Context mContext;
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
106a8571f15c39da2b7c6e672fef26106f5ac60dea0Jaikumar Ganesh    static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1083fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    private static final String DOCK_ADDRESS_PATH = "/sys/class/switch/dock/bt_addr";
1093fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    private static final String DOCK_PIN_PATH = "/sys/class/switch/dock/bt_pin";
1103fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
1116e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh    private static final String SHARED_PREFERENCE_DOCK_ADDRESS = "dock_bluetooth_address";
1126e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh    private static final String SHARED_PREFERENCES_NAME = "bluetooth_service_settings";
1136e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh
11484690c88f37f395094147d27ace8319a2803a522Jaikumar Ganesh    private static final int MESSAGE_FINISH_DISABLE = 1;
11584690c88f37f395094147d27ace8319a2803a522Jaikumar Ganesh    private static final int MESSAGE_UUID_INTENT = 2;
116fbb238db719cbae98afcb897f509b02edf58b062Jaikumar Ganesh    private static final int MESSAGE_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 3;
117a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh
118a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    // The time (in millisecs) to delay the pairing attempt after the first
119a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    // auto pairing attempt fails. We use an exponential delay with
120a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    // INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY as the initial value and
121a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    // MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY as the max value.
122a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    private static final long INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 3000;
123a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    private static final long MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 12000;
1241caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
1251caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    // The timeout used to sent the UUIDs Intent
1261caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    // This timeout should be greater than the page timeout
1271caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    private static final int UUID_INTENT_DELAY = 6000;
128105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
12916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    /** Always retrieve RFCOMM channel for these SDP UUIDs */
13016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private static final ParcelUuid[] RFCOMM_UUIDS = {
13116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            BluetoothUuid.Handsfree,
13216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            BluetoothUuid.HSP,
13316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            BluetoothUuid.ObexObjectPush };
13416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
1359a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    private final BluetoothAdapterProperties mAdapterProperties;
1369a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    private final BluetoothDeviceProperties mDeviceProperties;
137d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
13816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private final HashMap<String, Map<ParcelUuid, Integer>> mDeviceServiceChannelCache;
13916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private final ArrayList<String> mUuidIntentTracker;
14016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private final HashMap<RemoteService, IBluetoothCallback> mUuidCallbackTracker;
1411caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
14224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private final HashMap<Integer, Integer> mServiceRecordToPid;
14324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
144f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh    private final HashMap<String, BluetoothDeviceProfileState> mDeviceProfileState;
145f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh    private final BluetoothProfileState mA2dpProfileState;
146f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh    private final BluetoothProfileState mHfpProfileState;
1479b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
1489b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    private BluetoothA2dpService mA2dpService;
149cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    private final HashMap<String, Pair<byte[], byte[]>> mDeviceOobData;
150545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh
151a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh    private int mProfilesConnected = 0, mProfilesConnecting = 0, mProfilesDisconnecting = 0;
152707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh
1533fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    private static String mDockAddress;
1543fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    private String mDockPin;
1553fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
156c53cab20b225ba69057441ecb06db6478ab8ff9bJaikumar Ganesh    private int mAdapterConnectionState = BluetoothAdapter.STATE_DISCONNECTED;
157a8571f15c39da2b7c6e672fef26106f5ac60dea0Jaikumar Ganesh    private BluetoothPanProfileHandler mBluetoothPanProfileHandler;
15830b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    private BluetoothInputProfileHandler mBluetoothInputProfileHandler;
1592ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    private BluetoothHealthProfileHandler mBluetoothHealthProfileHandler;
160a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    private static final String INCOMING_CONNECTION_FILE =
161a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie      "/data/misc/bluetooth/incoming_connection.conf";
162a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    private HashMap<String, Pair<Integer, String>> mIncomingConnections;
163c53cab20b225ba69057441ecb06db6478ab8ff9bJaikumar Ganesh
16416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private static class RemoteService {
16516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        public String address;
16616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        public ParcelUuid uuid;
16716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        public RemoteService(String address, ParcelUuid uuid) {
16816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            this.address = address;
16916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            this.uuid = uuid;
17016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
17116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        @Override
17216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        public boolean equals(Object o) {
17316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (o instanceof RemoteService) {
17416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                RemoteService service = (RemoteService)o;
17516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                return address.equals(service.address) && uuid.equals(service.uuid);
17616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
17716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            return false;
17816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
1795f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root
1805f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root        @Override
1815f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root        public int hashCode() {
1825f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root            int hash = 1;
1835f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root            hash = hash * 31 + (address == null ? 0 : address.hashCode());
1845f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root            hash = hash * 31 + (uuid == null ? 0 : uuid.hashCode());
1855f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root            return hash;
1865f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root        }
18716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    }
18816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static {
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        classInitNative();
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
193bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    public BluetoothService(Context context) {
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext = context;
195105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
196105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Need to do this in place of:
197105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // mBatteryStats = BatteryStatsService.getService();
198105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Since we can not import BatteryStatsService from here. This class really needs to be
199105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // moved to java/services/com/android/server/
200105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo"));
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        initializeNativeDataNative();
203ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project
204ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project        if (isEnabledNative() == 1) {
205ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project            Log.w(TAG, "Bluetooth daemons already running - runtime restart? ");
206ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project            disableNative();
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
208ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project
209de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        mBluetoothState = BluetoothAdapter.STATE_OFF;
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mIsDiscovering = false;
211a8571f15c39da2b7c6e672fef26106f5ac60dea0Jaikumar Ganesh
2129a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        mBondState = new BluetoothBondState(context, this);
2139a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        mAdapterProperties = new BluetoothAdapterProperties(context, this);
2149a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        mDeviceProperties = new BluetoothDeviceProperties(this);
21510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
21610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        mDeviceServiceChannelCache = new HashMap<String, Map<ParcelUuid, Integer>>();
217cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        mDeviceOobData = new HashMap<String, Pair<byte[], byte[]>>();
2181caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        mUuidIntentTracker = new ArrayList<String>();
21916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        mUuidCallbackTracker = new HashMap<RemoteService, IBluetoothCallback>();
22024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        mServiceRecordToPid = new HashMap<Integer, Integer>();
221f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        mDeviceProfileState = new HashMap<String, BluetoothDeviceProfileState>();
222f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        mA2dpProfileState = new BluetoothProfileState(mContext, BluetoothProfileState.A2DP);
223f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        mHfpProfileState = new BluetoothProfileState(mContext, BluetoothProfileState.HFP);
224f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh
225f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        mHfpProfileState.start();
226f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        mA2dpProfileState.start();
2273fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
2283fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        IntentFilter filter = new IntentFilter();
2296e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh        registerForAirplaneMode(filter);
2306e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh
2313fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        filter.addAction(Intent.ACTION_DOCK_EVENT);
2326e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh        mContext.registerReceiver(mReceiver, filter);
23330b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        mBluetoothInputProfileHandler = BluetoothInputProfileHandler.getInstance(mContext, this);
234a8571f15c39da2b7c6e672fef26106f5ac60dea0Jaikumar Ganesh        mBluetoothPanProfileHandler = BluetoothPanProfileHandler.getInstance(mContext, this);
2352ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        mBluetoothHealthProfileHandler = BluetoothHealthProfileHandler.getInstance(mContext, this);
236a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        mIncomingConnections = new HashMap<String, Pair<Integer, String>>();
2373fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    }
2383fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
2399b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public static synchronized String readDockBluetoothAddress() {
2403fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        if (mDockAddress != null) return mDockAddress;
2413fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
2423fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        BufferedInputStream file = null;
2433fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        String dockAddress;
2443fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        try {
2453fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            file = new BufferedInputStream(new FileInputStream(DOCK_ADDRESS_PATH));
2463fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            byte[] address = new byte[17];
2473fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            file.read(address);
2483fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            dockAddress = new String(address);
2493fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            dockAddress = dockAddress.toUpperCase();
2503fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            if (BluetoothAdapter.checkBluetoothAddress(dockAddress)) {
2513fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                mDockAddress = dockAddress;
2523fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                return mDockAddress;
2533fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            } else {
2549a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                Log.e(TAG, "CheckBluetoothAddress failed for car dock address: "
2559a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                        + dockAddress);
2563fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            }
2573fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        } catch (FileNotFoundException e) {
2589a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            Log.e(TAG, "FileNotFoundException while trying to read dock address");
2593fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        } catch (IOException e) {
2609a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            Log.e(TAG, "IOException while trying to read dock address");
2613fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        } finally {
2623fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            if (file != null) {
2633fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                try {
2643fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                    file.close();
2653fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                } catch (IOException e) {
2663fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                    // Ignore
2673fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                }
2683fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            }
2693fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        }
2703fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        mDockAddress = null;
2713fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        return null;
2723fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    }
2733fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
2743fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    private synchronized boolean writeDockPin() {
2753fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        BufferedWriter out = null;
2763fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        try {
2773fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            out = new BufferedWriter(new FileWriter(DOCK_PIN_PATH));
2783fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
2793fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            // Generate a random 4 digit pin between 0000 and 9999
2803fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            // This is not truly random but good enough for our purposes.
2813fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            int pin = (int) Math.floor(Math.random() * 10000);
2823fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
2833fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            mDockPin = String.format("%04d", pin);
2843fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            out.write(mDockPin);
2853fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            return true;
2863fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        } catch (FileNotFoundException e) {
2879a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            Log.e(TAG, "FileNotFoundException while trying to write dock pairing pin");
2883fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        } catch (IOException e) {
2899a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            Log.e(TAG, "IOException while while trying to write dock pairing pin");
2903fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        } finally {
2913fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            if (out != null) {
2923fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                try {
2933fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                    out.close();
2943fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                } catch (IOException e) {
2953fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                    // Ignore
2963fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                }
2973fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            }
2983fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        }
2993fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        mDockPin = null;
3003fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        return false;
3013fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    }
3023fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
3033fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    /*package*/ synchronized String getDockPin() {
3043fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        return mDockPin;
305bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    }
306bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly
307bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    public synchronized void initAfterRegistration() {
308f242b7b931898856bcbcb7ec36cacf43098ba544Nick Pelly        mAdapter = BluetoothAdapter.getDefaultAdapter();
309bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mEventLoop = new BluetoothEventLoop(mContext, mAdapter, this);
3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3127d0548d0944e48421857de4aec2822ced325bea0Jaikumar Ganesh    public synchronized void initAfterA2dpRegistration() {
3137d0548d0944e48421857de4aec2822ced325bea0Jaikumar Ganesh        mEventLoop.getProfileProxy();
3147d0548d0944e48421857de4aec2822ced325bea0Jaikumar Ganesh    }
3157d0548d0944e48421857de4aec2822ced325bea0Jaikumar Ganesh
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void finalize() throws Throwable {
3186e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh        mContext.unregisterReceiver(mReceiver);
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            cleanupNativeDataNative();
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super.finalize();
3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean isEnabled() {
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
3288c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        return isEnabledInternal();
3298c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh    }
3308c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
3318c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh    private boolean isEnabledInternal() {
332de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        return mBluetoothState == BluetoothAdapter.STATE_ON;
3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
335105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    public int getBluetoothState() {
336105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
337105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        return mBluetoothState;
338105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    }
339105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
3409a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    int getBluetoothStateInternal() {
3419a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        return mBluetoothState;
3429a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    }
343105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Bring down bluetooth and disable BT in settings. Returns true on success.
3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean disable() {
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return disable(true);
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Bring down bluetooth. Returns true on success.
3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
354e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly     * @param saveSetting If true, persist the new setting
3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean disable(boolean saveSetting) {
357e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission");
3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
359105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        switch (mBluetoothState) {
360de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_OFF:
361105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return true;
362de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_ON:
363105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            break;
364105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        default:
365105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return false;
366105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mEnableThread != null && mEnableThread.isAlive()) {
3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
37084690c88f37f395094147d27ace8319a2803a522Jaikumar Ganesh
371de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        setBluetoothState(BluetoothAdapter.STATE_TURNING_OFF);
37284690c88f37f395094147d27ace8319a2803a522Jaikumar Ganesh
37384690c88f37f395094147d27ace8319a2803a522Jaikumar Ganesh        if (mAdapterSdpHandles != null) removeReservedServiceRecordsNative(mAdapterSdpHandles);
37474ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh        setBluetoothTetheringNative(false, BluetoothPanProfileHandler.NAP_ROLE,
37574ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                BluetoothPanProfileHandler.NAP_BRIDGE);
376105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
377105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Allow 3 seconds for profiles to gracefully disconnect
378105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // TODO: Introduce a callback mechanism so that each profile can notify
379bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        // BluetoothService when it is done shutting down
3807a0f816916abb200d9337a5afde5d6d2a637a20aJaikumar Ganesh        disconnectDevices();
3817a0f816916abb200d9337a5afde5d6d2a637a20aJaikumar Ganesh
382105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mHandler.sendMessageDelayed(
383105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                mHandler.obtainMessage(MESSAGE_FINISH_DISABLE, saveSetting ? 1 : 0, 0), 3000);
384105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        return true;
385105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    }
386105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
3877a0f816916abb200d9337a5afde5d6d2a637a20aJaikumar Ganesh    private synchronized void disconnectDevices() {
3887a0f816916abb200d9337a5afde5d6d2a637a20aJaikumar Ganesh        // Disconnect devices handled by BluetoothService.
3897a0f816916abb200d9337a5afde5d6d2a637a20aJaikumar Ganesh        for (BluetoothDevice device: getConnectedInputDevices()) {
3907a0f816916abb200d9337a5afde5d6d2a637a20aJaikumar Ganesh            disconnectInputDevice(device);
3917a0f816916abb200d9337a5afde5d6d2a637a20aJaikumar Ganesh        }
3927a0f816916abb200d9337a5afde5d6d2a637a20aJaikumar Ganesh
3937a0f816916abb200d9337a5afde5d6d2a637a20aJaikumar Ganesh        for (BluetoothDevice device: getConnectedPanDevices()) {
3947a0f816916abb200d9337a5afde5d6d2a637a20aJaikumar Ganesh            disconnectPanDevice(device);
3957a0f816916abb200d9337a5afde5d6d2a637a20aJaikumar Ganesh        }
3967a0f816916abb200d9337a5afde5d6d2a637a20aJaikumar Ganesh    }
397105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
398105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private synchronized void finishDisable(boolean saveSetting) {
399de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        if (mBluetoothState != BluetoothAdapter.STATE_TURNING_OFF) {
400105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return;
4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mEventLoop.stop();
403d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        tearDownNativeDataNative();
4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        disableNative();
4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // mark in progress bondings as cancelled
4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (String address : mBondState.listInState(BluetoothDevice.BOND_BONDING)) {
408005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            mBondState.setBondState(address, BluetoothDevice.BOND_NONE,
4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4122d1fc4e3f5eb612f9ef8a50080310ced1dfaaadfJaikumar Ganesh        // Stop the profile state machine for bonded devices.
4132d1fc4e3f5eb612f9ef8a50080310ced1dfaaadfJaikumar Ganesh        for (String address : mBondState.listInState(BluetoothDevice.BOND_BONDED)) {
4142d1fc4e3f5eb612f9ef8a50080310ced1dfaaadfJaikumar Ganesh            removeProfileState(address);
4152d1fc4e3f5eb612f9ef8a50080310ced1dfaaadfJaikumar Ganesh        }
4162d1fc4e3f5eb612f9ef8a50080310ced1dfaaadfJaikumar Ganesh
4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // update mode
418de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        Intent intent = new Intent(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
419de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        intent.putExtra(BluetoothAdapter.EXTRA_SCAN_MODE, BluetoothAdapter.SCAN_MODE_NONE);
4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.sendBroadcast(intent, BLUETOOTH_PERM);
4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
422105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mIsDiscovering = false;
423bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mAdapterProperties.clear();
42424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        mServiceRecordToPid.clear();
425105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
426a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh        mProfilesConnected = 0;
427a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh        mProfilesConnecting = 0;
428a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh        mProfilesDisconnecting = 0;
429c53cab20b225ba69057441ecb06db6478ab8ff9bJaikumar Ganesh        mAdapterConnectionState = BluetoothAdapter.STATE_DISCONNECTED;
43050b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        mAdapterUuids = null;
43150b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        mAdapterSdpHandles = null;
432a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh
4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (saveSetting) {
4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            persistBluetoothOnSetting(false);
4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
436105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
437de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        setBluetoothState(BluetoothAdapter.STATE_OFF);
438105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
439105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Log bluetooth off to battery stats.
440105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        long ident = Binder.clearCallingIdentity();
441105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        try {
442105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            mBatteryStats.noteBluetoothOff();
443105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        } catch (RemoteException e) {
444105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        } finally {
445105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            Binder.restoreCallingIdentity(ident);
446105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
447997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly
448997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        if (mRestart) {
449997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly            mRestart = false;
450997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly            enable();
451997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        }
4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
454105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    /** Bring up BT and persist BT on in settings */
455105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    public boolean enable() {
456105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        return enable(true);
4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Enable this Bluetooth device, asynchronously.
4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * This turns on/off the underlying hardware.
4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
463105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project     * @param saveSetting If true, persist the new state of BT in settings
464105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project     * @return True on success (so far)
4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
466105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    public synchronized boolean enable(boolean saveSetting) {
4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Airplane mode can prevent Bluetooth radio from being turned on.
47144303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        if (mIsAirplaneSensitive && isAirplaneModeOn() && !mIsAirplaneToggleable) {
4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
474de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        if (mBluetoothState != BluetoothAdapter.STATE_OFF) {
4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mEnableThread != null && mEnableThread.isAlive()) {
4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
480de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        setBluetoothState(BluetoothAdapter.STATE_TURNING_ON);
481105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mEnableThread = new EnableThread(saveSetting);
4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mEnableThread.start();
4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
486997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly    /** Forcibly restart Bluetooth if it is on */
487997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly    /* package */ synchronized void restart() {
488de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        if (mBluetoothState != BluetoothAdapter.STATE_ON) {
489997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly            return;
490997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        }
491997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        mRestart = true;
492997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        if (!disable(false)) {
493997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly            mRestart = false;
494997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        }
495d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
496997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly
497105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private synchronized void setBluetoothState(int state) {
498105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        if (state == mBluetoothState) {
499105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return;
500105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
501105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
5029a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        if (DBG) Log.d(TAG, "Bluetooth state " + mBluetoothState + " -> " + state);
503105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
504de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
505de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, mBluetoothState);
506de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        intent.putExtra(BluetoothAdapter.EXTRA_STATE, state);
507105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
508105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
509105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mBluetoothState = state;
510105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
511105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mContext.sendBroadcast(intent, BLUETOOTH_PERM);
512105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    }
513105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final Handler mHandler = new Handler() {
5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void handleMessage(Message msg) {
5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            switch (msg.what) {
518105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            case MESSAGE_FINISH_DISABLE:
519105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                finishDisable(msg.arg1 != 0);
520105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                break;
5211caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            case MESSAGE_UUID_INTENT:
5221caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh                String address = (String)msg.obj;
52316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (address != null) {
5241caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh                    sendUuidIntent(address);
52516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    makeServiceChannelCallbacks(address);
52616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                }
5271caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh                break;
528a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            case MESSAGE_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY:
529a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                address = (String)msg.obj;
5308adcacbf83697d1299812f5365380b097898567aJaikumar Ganesh                if (address == null) return;
5318adcacbf83697d1299812f5365380b097898567aJaikumar Ganesh                int attempt = mBondState.getAttempt(address);
5328adcacbf83697d1299812f5365380b097898567aJaikumar Ganesh
5338adcacbf83697d1299812f5365380b097898567aJaikumar Ganesh                // Try only if attemps are in progress and cap it 2 attempts
5348adcacbf83697d1299812f5365380b097898567aJaikumar Ganesh                // The 2 attempts cap is a fail safe if the stack returns
5358adcacbf83697d1299812f5365380b097898567aJaikumar Ganesh                // an incorrect error code for bonding failures and if the pin
5368adcacbf83697d1299812f5365380b097898567aJaikumar Ganesh                // is entered wrongly twice we should abort.
5378adcacbf83697d1299812f5365380b097898567aJaikumar Ganesh                if (attempt > 0 && attempt <= 2) {
5388adcacbf83697d1299812f5365380b097898567aJaikumar Ganesh                    mBondState.attempt(address);
539a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                    createBond(address);
540a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                    return;
541a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                }
5428adcacbf83697d1299812f5365380b097898567aJaikumar Ganesh                if (attempt > 0) mBondState.clearPinAttempts(address);
543a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                break;
5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private EnableThread mEnableThread;
5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private class EnableThread extends Thread {
5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final boolean mSaveSetting;
552105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        public EnableThread(boolean saveSetting) {
5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mSaveSetting = saveSetting;
5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void run() {
5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean res = (enableNative() == 0);
5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (res) {
558b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                int retryCount = 2;
559b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                boolean running = false;
560b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                while ((retryCount-- > 0) && !running) {
561b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    mEventLoop.start();
5629a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                    // it may take a moment for the other thread to do its
563b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    // thing.  Check periodically for a while.
564b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    int pollCount = 5;
565b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    while ((pollCount-- > 0) && !running) {
566b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                        if (mEventLoop.isEventLoopRunning()) {
567b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                            running = true;
568b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                            break;
569b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                        }
570b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                        try {
571b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                            Thread.sleep(100);
572b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                        } catch (InterruptedException e) {}
573b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    }
574b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                }
575b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                if (!running) {
5769a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                    Log.e(TAG, "bt EnableThread giving up");
577b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    res = false;
578b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    disableNative();
579b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                }
5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (res) {
583d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                if (!setupNativeDataNative()) {
584d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                    return;
585d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                }
5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mSaveSetting) {
5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    persistBluetoothOnSetting(true);
5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
58984690c88f37f395094147d27ace8319a2803a522Jaikumar Ganesh
59084690c88f37f395094147d27ace8319a2803a522Jaikumar Ganesh                mIsDiscovering = false;
59184690c88f37f395094147d27ace8319a2803a522Jaikumar Ganesh                mBondState.readAutoPairingData();
592c73dd732c962238330cc2e5538a88bffbbb40fe8Jaikumar Ganesh                mBondState.initBondState();
59384690c88f37f395094147d27ace8319a2803a522Jaikumar Ganesh                initProfileState();
5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5959efb1343a018c479ff57d70e8058658faa8a926dJaikumar Ganesh                // This should be the last step of the the enable thread.
5969efb1343a018c479ff57d70e8058658faa8a926dJaikumar Ganesh                // Because this adds SDP records which asynchronously
5979efb1343a018c479ff57d70e8058658faa8a926dJaikumar Ganesh                // broadcasts the Bluetooth On State in updateBluetoothState.
5989efb1343a018c479ff57d70e8058658faa8a926dJaikumar Ganesh                // So we want all internal state setup before this.
5999efb1343a018c479ff57d70e8058658faa8a926dJaikumar Ganesh                updateSdpRecords();
60050b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh            } else {
60150b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh                setBluetoothState(BluetoothAdapter.STATE_OFF);
6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
603105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            mEnableThread = null;
60450b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        }
60550b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh    }
606105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
60750b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh    private synchronized void addReservedSdpRecords(final ArrayList<ParcelUuid> uuids) {
60850b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        //Register SDP records.
60950b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        int[] svcIdentifiers = new int[uuids.size()];
61050b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        for (int i = 0; i < uuids.size(); i++) {
61150b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh            svcIdentifiers[i] = BluetoothUuid.getServiceIdentifierFromParcelUuid(uuids.get(i));
61250b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        }
61350b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        mAdapterSdpHandles = addReservedServiceRecordsNative(svcIdentifiers);
61450b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh    }
615105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
61650b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh    private synchronized void updateSdpRecords() {
61750b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        ArrayList<ParcelUuid> uuids = new ArrayList<ParcelUuid>();
61850b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh
61950b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        // Add the default records
62050b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        uuids.add(BluetoothUuid.HSP_AG);
62150b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        uuids.add(BluetoothUuid.ObexObjectPush);
62250b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh
62350b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        if (mContext.getResources().
62450b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh                getBoolean(com.android.internal.R.bool.config_voice_capable)) {
62550b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh            uuids.add(BluetoothUuid.Handsfree_AG);
62650b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh            uuids.add(BluetoothUuid.PBAP_PSE);
62750b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        }
62850b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh
62950b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        // Add SDP records for profiles maintained by Android userspace
63050b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        addReservedSdpRecords(uuids);
63150b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh
63250b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        // Enable profiles maintained by Bluez userspace.
63374ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh        setBluetoothTetheringNative(true, BluetoothPanProfileHandler.NAP_ROLE,
63474ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                BluetoothPanProfileHandler.NAP_BRIDGE);
63550b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh
63650b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        // Add SDP records for profiles maintained by Bluez userspace
63750b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        uuids.add(BluetoothUuid.AudioSource);
63850b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        uuids.add(BluetoothUuid.AvrcpTarget);
63950b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        uuids.add(BluetoothUuid.NAP);
64050b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh
64150b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        // Cannot cast uuids.toArray directly since ParcelUuid is parcelable
64250b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        mAdapterUuids = new ParcelUuid[uuids.size()];
64350b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        for (int i = 0; i < uuids.size(); i++) {
64450b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh            mAdapterUuids[i] = uuids.get(i);
64550b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        }
64650b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh    }
64750b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh
6489efb1343a018c479ff57d70e8058658faa8a926dJaikumar Ganesh    /**
6499efb1343a018c479ff57d70e8058658faa8a926dJaikumar Ganesh     * This function is called from Bluetooth Event Loop when onPropertyChanged
6509efb1343a018c479ff57d70e8058658faa8a926dJaikumar Ganesh     * for adapter comes in with UUID property.
6519efb1343a018c479ff57d70e8058658faa8a926dJaikumar Ganesh     * @param uuidsThe uuids of adapter as reported by Bluez.
6529efb1343a018c479ff57d70e8058658faa8a926dJaikumar Ganesh     */
65350b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh    synchronized void updateBluetoothState(String uuids) {
65450b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        if (mBluetoothState == BluetoothAdapter.STATE_TURNING_ON) {
65550b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh            ParcelUuid[] adapterUuids = convertStringToParcelUuid(uuids);
65650b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh
65750b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh            if (mAdapterUuids != null &&
65850b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh                    BluetoothUuid.containsAllUuids(adapterUuids, mAdapterUuids)) {
65950b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh                setBluetoothState(BluetoothAdapter.STATE_ON);
6609a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                autoConnect();
661d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                String[] propVal = {"Pairable", getProperty("Pairable")};
662d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                mEventLoop.onPropertyChanged(propVal);
663b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project
6649efb1343a018c479ff57d70e8058658faa8a926dJaikumar Ganesh                // Log bluetooth on to battery stats.
6659efb1343a018c479ff57d70e8058658faa8a926dJaikumar Ganesh                long ident = Binder.clearCallingIdentity();
6669efb1343a018c479ff57d70e8058658faa8a926dJaikumar Ganesh                try {
6679efb1343a018c479ff57d70e8058658faa8a926dJaikumar Ganesh                    mBatteryStats.noteBluetoothOn();
6689efb1343a018c479ff57d70e8058658faa8a926dJaikumar Ganesh                } catch (RemoteException e) {
6699efb1343a018c479ff57d70e8058658faa8a926dJaikumar Ganesh                } finally {
6709efb1343a018c479ff57d70e8058658faa8a926dJaikumar Ganesh                    Binder.restoreCallingIdentity(ident);
6719efb1343a018c479ff57d70e8058658faa8a926dJaikumar Ganesh                }
6729efb1343a018c479ff57d70e8058658faa8a926dJaikumar Ganesh
67350b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh                if (mIsAirplaneSensitive && isAirplaneModeOn() && !mIsAirplaneToggleable) {
67450b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh                    disable(false);
67550b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh                }
6765c43f735d94a538dc273c8f859d1100a7cdd5c71Daisuke Miyakawa            }
6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void persistBluetoothOnSetting(boolean bluetoothOn) {
6819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long origCallerIdentityToken = Binder.clearCallingIdentity();
6829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.BLUETOOTH_ON,
6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                bluetoothOn ? 1 : 0);
6849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Binder.restoreCallingIdentity(origCallerIdentityToken);
6859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
687a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    /*package*/ synchronized boolean attemptAutoPair(String address) {
688a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        if (!mBondState.hasAutoPairingFailed(address) &&
689a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                !mBondState.isAutoPairingBlacklisted(address)) {
690a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            mBondState.attempt(address);
691a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            setPin(address, BluetoothDevice.convertPinToBytes("0000"));
692a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            return true;
693a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        }
694a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        return false;
695a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    }
696a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh
697f487d72215421a02e5a1b2fbff4618bc5ee185cbJaikumar Ganesh    /*package*/ synchronized boolean isFixedPinZerosAutoPairKeyboard(String address) {
698f487d72215421a02e5a1b2fbff4618bc5ee185cbJaikumar Ganesh        // Check for keyboards which have fixed PIN 0000 as the pairing pin
699f487d72215421a02e5a1b2fbff4618bc5ee185cbJaikumar Ganesh        return mBondState.isFixedPinZerosAutoPairKeyboard(address);
700f487d72215421a02e5a1b2fbff4618bc5ee185cbJaikumar Ganesh    }
701f487d72215421a02e5a1b2fbff4618bc5ee185cbJaikumar Ganesh
702a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    /*package*/ synchronized void onCreatePairedDeviceResult(String address, int result) {
703a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        if (result == BluetoothDevice.BOND_SUCCESS) {
704a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            setBondState(address, BluetoothDevice.BOND_BONDED);
705a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            if (mBondState.isAutoPairingAttemptsInProgress(address)) {
706a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                mBondState.clearPinAttempts(address);
707a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            }
708a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        } else if (result == BluetoothDevice.UNBOND_REASON_AUTH_FAILED &&
709a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                mBondState.getAttempt(address) == 1) {
710a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            mBondState.addAutoPairingFailure(address);
711a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            pairingAttempt(address, result);
712a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        } else if (result == BluetoothDevice.UNBOND_REASON_REMOTE_DEVICE_DOWN &&
713a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh              mBondState.isAutoPairingAttemptsInProgress(address)) {
714a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            pairingAttempt(address, result);
715a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        } else {
716a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            setBondState(address, BluetoothDevice.BOND_NONE, result);
717a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            if (mBondState.isAutoPairingAttemptsInProgress(address)) {
718a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                mBondState.clearPinAttempts(address);
719a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            }
720a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        }
721a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    }
722a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh
723a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    /*package*/ synchronized String getPendingOutgoingBonding() {
724a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        return mBondState.getPendingOutgoingBonding();
725a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    }
726a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh
727a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    private void pairingAttempt(String address, int result) {
728a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        // This happens when our initial guess of "0000" as the pass key
729a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        // fails. Try to create the bond again and display the pin dialog
730a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        // to the user. Use back-off while posting the delayed
731a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        // message. The initial value is
732a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        // INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY and the max value is
733a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        // MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY. If the max value is
734a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        // reached, display an error to the user.
735a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        int attempt = mBondState.getAttempt(address);
736a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        if (attempt * INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY >
737a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                    MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY) {
738a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            mBondState.clearPinAttempts(address);
739a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            setBondState(address, BluetoothDevice.BOND_NONE, result);
740a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            return;
741a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        }
742a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh
743a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        Message message = mHandler.obtainMessage(MESSAGE_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY);
744a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        message.obj = address;
745a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        boolean postResult =  mHandler.sendMessageDelayed(message,
746a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                                        attempt * INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY);
747a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        if (!postResult) {
748a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            mBondState.clearPinAttempts(address);
749a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            setBondState(address,
750a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                    BluetoothDevice.BOND_NONE, result);
751a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            return;
752a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        }
7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7559a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    /*package*/ BluetoothDevice getRemoteDevice(String address) {
7569a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        return mAdapter.getRemoteDevice(address);
7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static String toBondStateString(int bondState) {
7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        switch (bondState) {
761005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        case BluetoothDevice.BOND_NONE:
7629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "not bonded";
7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case BluetoothDevice.BOND_BONDING:
7649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "bonding";
7659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case BluetoothDevice.BOND_BONDED:
7669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "bonded";
7679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        default:
7689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "??????";
7699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean setName(String name) {
7739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
7749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
7759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (name == null) {
7769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
7779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
778d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setPropertyString("Name", name);
7799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
781d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    //TODO(): setPropertyString, setPropertyInteger, setPropertyBoolean
782d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    // Either have a single property function with Object as the parameter
783d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    // or have a function for each property and then obfuscate in the JNI layer.
784d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    // The following looks dirty.
785d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private boolean setPropertyString(String key, String value) {
7869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
7878c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
788d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setAdapterPropertyStringNative(key, value);
7899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
791d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private boolean setPropertyInteger(String key, int value) {
792d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
7938c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
794d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setAdapterPropertyIntegerNative(key, value);
795d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
7969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
797d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private boolean setPropertyBoolean(String key, boolean value) {
798d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
7998c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
800d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setAdapterPropertyBooleanNative(key, value ? 1 : 0);
8019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
803d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /**
804d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Set the discoverability window for the device.  A timeout of zero
805d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * makes the device permanently discoverable (if the device is
806d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * discoverable).  Setting the timeout to a nonzero value does not make
807d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * a device discoverable; you need to call setMode() to make the device
808d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * explicitly discoverable.
809d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     *
810f51eadaf1f83abfe16a609a4ded6d789494689b2Jake Hamby     * @param timeout The discoverable timeout in seconds.
811d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     */
812d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized boolean setDiscoverableTimeout(int timeout) {
8139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
8149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
815d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setPropertyInteger("DiscoverableTimeout", timeout);
8169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
81812835478ee687a493d1b5882e67b6725bd539c26Nick Pelly    public synchronized boolean setScanMode(int mode, int duration) {
81918b1e79a123b979d25bfa5d0b0ee5d0382dbd64bNick Pelly        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS,
82018b1e79a123b979d25bfa5d0b0ee5d0382dbd64bNick Pelly                                                "Need WRITE_SECURE_SETTINGS permission");
8219a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        boolean pairable;
8229a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        boolean discoverable;
82312835478ee687a493d1b5882e67b6725bd539c26Nick Pelly
824de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        switch (mode) {
825de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.SCAN_MODE_NONE:
826d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            pairable = false;
827d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            discoverable = false;
828de893f550301a60274e87aa8168225e7a7a42184Nick Pelly            break;
829de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
830d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            pairable = true;
831d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            discoverable = false;
832005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            break;
833de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
834d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            pairable = true;
835d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            discoverable = true;
83612835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            if (DBG) Log.d(TAG, "BT Discoverable for " + duration + " seconds");
837005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            break;
838de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        default:
839de893f550301a60274e87aa8168225e7a7a42184Nick Pelly            Log.w(TAG, "Requested invalid scan mode " + mode);
840de893f550301a60274e87aa8168225e7a7a42184Nick Pelly            return false;
841d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
842d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        setPropertyBoolean("Pairable", pairable);
843d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        setPropertyBoolean("Discoverable", discoverable);
8449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
845d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return true;
8469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
848b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh    /*package*/ synchronized String getProperty(String name) {
849b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh        if (!isEnabledInternal()) return null;
8509a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        return mAdapterProperties.getProperty(name);
851b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh    }
852b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh
8539a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    BluetoothAdapterProperties getAdapterProperties() {
8549a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        return mAdapterProperties;
8559a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    }
8569a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
8579a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    BluetoothDeviceProperties getDeviceProperties() {
8589a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        return mDeviceProperties;
8599a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    }
8609a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
8619a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    boolean isRemoteDeviceInCache(String address) {
8629a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        return mDeviceProperties.isInCache(address);
8639a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    }
8649a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
8659a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    void setRemoteDeviceProperty(String address, String name, String value) {
8669a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        mDeviceProperties.setProperty(address, name, value);
8679a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    }
8689a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
8699a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    void updateRemoteDevicePropertiesCache(String address) {
8709a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        mDeviceProperties.updateCache(address);
8719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
873d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized String getAddress() {
874d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
875d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return getProperty("Address");
8769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
878d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized String getName() {
8799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
880d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return getProperty("Name");
8819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
88358b93c36409c7fb91a644605f004b6d247d9b540Jaikumar Ganesh    public synchronized ParcelUuid[] getUuids() {
88458b93c36409c7fb91a644605f004b6d247d9b540Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
88558b93c36409c7fb91a644605f004b6d247d9b540Jaikumar Ganesh        String value =  getProperty("UUIDs");
88658b93c36409c7fb91a644605f004b6d247d9b540Jaikumar Ganesh        if (value == null) return null;
88750b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        return convertStringToParcelUuid(value);
88850b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh    }
88958b93c36409c7fb91a644605f004b6d247d9b540Jaikumar Ganesh
89050b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh    private synchronized ParcelUuid[] convertStringToParcelUuid(String value) {
89158b93c36409c7fb91a644605f004b6d247d9b540Jaikumar Ganesh        String[] uuidStrings = null;
89258b93c36409c7fb91a644605f004b6d247d9b540Jaikumar Ganesh        // The UUIDs are stored as a "," separated string.
89358b93c36409c7fb91a644605f004b6d247d9b540Jaikumar Ganesh        uuidStrings = value.split(",");
89458b93c36409c7fb91a644605f004b6d247d9b540Jaikumar Ganesh        ParcelUuid[] uuids = new ParcelUuid[uuidStrings.length];
89558b93c36409c7fb91a644605f004b6d247d9b540Jaikumar Ganesh
89658b93c36409c7fb91a644605f004b6d247d9b540Jaikumar Ganesh        for (int i = 0; i < uuidStrings.length; i++) {
89758b93c36409c7fb91a644605f004b6d247d9b540Jaikumar Ganesh            uuids[i] = ParcelUuid.fromString(uuidStrings[i]);
89858b93c36409c7fb91a644605f004b6d247d9b540Jaikumar Ganesh        }
89958b93c36409c7fb91a644605f004b6d247d9b540Jaikumar Ganesh        return uuids;
90058b93c36409c7fb91a644605f004b6d247d9b540Jaikumar Ganesh    }
90158b93c36409c7fb91a644605f004b6d247d9b540Jaikumar Ganesh
90258b93c36409c7fb91a644605f004b6d247d9b540Jaikumar Ganesh
9039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
904d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Returns the user-friendly name of a remote device.  This value is
905d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * returned from our local cache, which is updated when onPropertyChange
906d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * event is received.
907d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Do not expect to retrieve the updated remote name immediately after
908d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * changing the name on the remote device.
9099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
910d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * @param address Bluetooth address of remote device.
911d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     *
912d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * @return The user-friendly name of the specified remote device.
9139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
914d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized String getRemoteName(String address) {
915d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
916005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
917d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return null;
918d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
9199a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        return mDeviceProperties.getProperty(address, "Name");
9209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
9239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Get the discoverability window for the device.  A timeout of zero
9249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * means that the device is permanently discoverable (if the device is
9259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * in the discoverable mode).
9269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
9279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The discoverability window of the device, in seconds.  A negative
9289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         value indicates an error.
9299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
9309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized int getDiscoverableTimeout() {
9319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
932d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String timeout = getProperty("DiscoverableTimeout");
933d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (timeout != null)
934d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh           return Integer.valueOf(timeout);
935d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        else
936d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return -1;
9379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized int getScanMode() {
9409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
9418c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal())
942de893f550301a60274e87aa8168225e7a7a42184Nick Pelly            return BluetoothAdapter.SCAN_MODE_NONE;
943d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
944d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        boolean pairable = getProperty("Pairable").equals("true");
945d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        boolean discoverable = getProperty("Discoverable").equals("true");
946d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return bluezStringToScanMode (pairable, discoverable);
9479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
949d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized boolean startDiscovery() {
9509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
9519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
9528c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
9538c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
954d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return startDiscoveryNative();
9559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
957d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized boolean cancelDiscovery() {
9589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
9599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
9608c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
9618c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
962d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return stopDiscoveryNative();
963d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
964d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
965d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized boolean isDiscovering() {
966d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
967d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return mIsDiscovering;
968d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
969d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
970d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ void setIsDiscovering(boolean isDiscovering) {
971d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mIsDiscovering = isDiscovering;
9729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
974cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    private boolean isBondingFeasible(String address) {
9759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
9769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
9778c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
9788c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
979005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
9809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
9819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        address = address.toUpperCase();
9839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9842092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        if (mBondState.getPendingOutgoingBonding() != null) {
9859a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            Log.d(TAG, "Ignoring createBond(): another device is bonding");
9869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // a different device is currently bonding, fail
9879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
9889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Check for bond state only if we are not performing auto
9919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // pairing exponential back-off attempts.
9929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mBondState.isAutoPairingAttemptsInProgress(address) &&
993005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly                mBondState.getBondState(address) != BluetoothDevice.BOND_NONE) {
9949a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            Log.d(TAG, "Ignoring createBond(): this device is already bonding or bonded");
9959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
9969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9983fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        if (address.equals(mDockAddress)) {
9993fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            if (!writeDockPin()) {
10009a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                Log.e(TAG, "Error while writing Pin for the dock");
10013fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                return false;
10023fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            }
10033fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        }
1004cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        return true;
1005cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    }
10063fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
1007cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    public synchronized boolean createBond(String address) {
1008cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (!isBondingFeasible(address)) return false;
1009cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
1010cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (!createPairedDeviceNative(address, 60000  /*1 minute*/ )) {
10119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
10129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10142092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        mBondState.setPendingOutgoingBonding(address);
10159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mBondState.setBondState(address, BluetoothDevice.BOND_BONDING);
10162092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
10179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
10189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1020cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    public synchronized boolean createBondOutOfBand(String address, byte[] hash,
1021cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh                                                    byte[] randomizer) {
1022cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (!isBondingFeasible(address)) return false;
10233fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
1024cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (!createPairedDeviceOutOfBandNative(address, 60000 /* 1 minute */)) {
10259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
10269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1028cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        setDeviceOutOfBandData(address, hash, randomizer);
10292092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        mBondState.setPendingOutgoingBonding(address);
10309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mBondState.setBondState(address, BluetoothDevice.BOND_BONDING);
10312092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
10329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
10339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1035cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    public synchronized boolean setDeviceOutOfBandData(String address, byte[] hash,
1036cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh            byte[] randomizer) {
1037cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1038cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh                                                "Need BLUETOOTH_ADMIN permission");
1039cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (!isEnabledInternal()) return false;
1040cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
1041cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        Pair <byte[], byte[]> value = new Pair<byte[], byte[]>(hash, randomizer);
1042cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
1043cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (DBG) {
10449a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            Log.d(TAG, "Setting out of band data for: " + address + ":" +
10459a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                  Arrays.toString(hash) + ":" + Arrays.toString(randomizer));
1046cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        }
1047cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
1048cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        mDeviceOobData.put(address, value);
1049cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        return true;
1050cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    }
1051cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
1052cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    Pair<byte[], byte[]> getDeviceOutOfBandData(BluetoothDevice device) {
1053cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        return mDeviceOobData.get(device.getAddress());
1054cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    }
1055cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
1056cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
1057cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    public synchronized byte[] readOutOfBandData() {
1058cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
1059cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh                                                "Need BLUETOOTH permission");
1060cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (!isEnabledInternal()) return null;
1061cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
1062cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        return readAdapterOutOfBandDataNative();
1063cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    }
1064cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
10659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean cancelBondProcess(String address) {
10669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
10679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
10688c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
10698c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1070005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
10719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
10729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        address = address.toUpperCase();
10749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mBondState.getBondState(address) != BluetoothDevice.BOND_BONDING) {
10759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
10769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1078005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        mBondState.setBondState(address, BluetoothDevice.BOND_NONE,
10799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
1080d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        cancelDeviceCreationNative(address);
10819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
10829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean removeBond(String address) {
10859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
10869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
10878c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
10888c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1089005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
10909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
10919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1092f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
10939b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (state != null) {
1094f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            state.sendMessage(BluetoothDeviceProfileState.UNPAIR);
10959b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            return true;
10969b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        } else {
10979b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            return false;
10989b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
10999b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
11009b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
11019b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public synchronized boolean removeBondInternal(String address) {
1102cc2c06656ceafbcd91ec5b679aa6c9eae0d9982cJaikumar Ganesh        // Unset the trusted device state and then unpair
1103cc2c06656ceafbcd91ec5b679aa6c9eae0d9982cJaikumar Ganesh        setTrust(address, false);
1104d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return removeDeviceNative(getObjectPathFromAddress(address));
11059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized String[] listBonds() {
11089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
11099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mBondState.listInState(BluetoothDevice.BOND_BONDED);
11109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1112a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    /*package*/ synchronized String[] listInState(int state) {
1113a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh      return mBondState.listInState(state);
1114a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    }
1115a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh
11169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized int getBondState(String address) {
11179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1118005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1119b24e11baac589fe16426f2d243b460ab84991c7bNick Pelly            return BluetoothDevice.ERROR;
11209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mBondState.getBondState(address.toUpperCase());
11229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1124a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    /*package*/ synchronized boolean setBondState(String address, int state) {
1125a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        return setBondState(address, state, 0);
1126a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    }
1127a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh
1128a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    /*package*/ synchronized boolean setBondState(String address, int state, int reason) {
1129ae5fbb0b4363a2a399e92e310777d7a955a25370Arek Lichwa        mBondState.setBondState(address.toUpperCase(), state, reason);
1130a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        return true;
1131a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    }
1132a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh
11333fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    public synchronized boolean isBluetoothDock(String address) {
11346e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh        SharedPreferences sp = mContext.getSharedPreferences(SHARED_PREFERENCES_NAME,
11359a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                Context.MODE_PRIVATE);
11366e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh
11376e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh        return sp.contains(SHARED_PREFERENCE_DOCK_ADDRESS + address);
11383fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    }
11393fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
11409488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh    /*package*/ String[] getRemoteDeviceProperties(String address) {
11418c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return null;
11428c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
11439488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh        String objectPath = getObjectPathFromAddress(address);
11449488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh        return (String [])getDevicePropertiesNative(objectPath);
11459488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh    }
11469488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh
11479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1148efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * Sets the remote device trust state.
1149efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     *
1150efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * @return boolean to indicate operation success or fail
1151efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     */
1152efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    public synchronized boolean setTrust(String address, boolean value) {
1153005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1154e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly            mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1155e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly                    "Need BLUETOOTH_ADMIN permission");
1156efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            return false;
1157efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        }
1158efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue
11598c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
11608c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
11619a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        return setDevicePropertyBooleanNative(
11629a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                getObjectPathFromAddress(address), "Trusted", value ? 1 : 0);
1163efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    }
1164efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue
1165efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    /**
1166efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * Gets the remote device trust state as boolean.
1167efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * Note: this value may be
1168efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * retrieved from cache if we retrieved the data before *
1169efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     *
11709a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * @return boolean to indicate trusted or untrusted state
1171efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     */
1172efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    public synchronized boolean getTrustState(String address) {
1173005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1174efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1175efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            return false;
1176efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        }
1177efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue
11789a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        String val = mDeviceProperties.getProperty(address, "Trusted");
1179efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        if (val == null) {
1180efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            return false;
1181efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        } else {
11829a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            return val.equals("true");
1183efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        }
1184efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    }
1185efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue
1186efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    /**
1187d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Gets the remote major, minor classes encoded as a 32-bit
11889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * integer.
11899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
11909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Note: this value is retrieved from cache, because we get it during
11919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *       remote-device discovery.
11929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
11939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return 32-bit integer encoding the remote major, minor, and service
11949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         classes.
11959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
11969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized int getRemoteClass(String address) {
1197005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1198ea600ccfb7568f60377c4abc85f56c80af7fdbfcNick Pelly            mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1199ea600ccfb7568f60377c4abc85f56c80af7fdbfcNick Pelly            return BluetoothClass.ERROR;
12009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12019a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        String val = mDeviceProperties.getProperty(address, "Class");
1202d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (val == null)
1203d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return BluetoothClass.ERROR;
1204d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        else {
1205d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return Integer.valueOf(val);
1206d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
12079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1208d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
12099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1211dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh     * Gets the UUIDs supported by the remote device
12129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1213dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh     * @return array of 128bit ParcelUuids
12149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1215dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh    public synchronized ParcelUuid[] getRemoteUuids(String address) {
12169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1217005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
12189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return null;
12199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12201caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        return getUuidFromCache(address);
12211caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    }
12221caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
12239a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    ParcelUuid[] getUuidFromCache(String address) {
12249a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        String value = mDeviceProperties.getProperty(address, "UUIDs");
1225dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        if (value == null) return null;
1226dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh
1227dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        String[] uuidStrings = null;
1228d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        // The UUIDs are stored as a "," separated string.
1229dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        uuidStrings = value.split(",");
1230dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        ParcelUuid[] uuids = new ParcelUuid[uuidStrings.length];
1231dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh
1232dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        for (int i = 0; i < uuidStrings.length; i++) {
1233dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh            uuids[i] = ParcelUuid.fromString(uuidStrings[i]);
1234dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        }
1235d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return uuids;
12369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
123816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    /**
123916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * Connect and fetch new UUID's using SDP.
124016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * The UUID's found are broadcast as intents.
124116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * Optionally takes a uuid and callback to fetch the RFCOMM channel for the
124216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * a given uuid.
124316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * TODO: Don't wait UUID_INTENT_DELAY to broadcast UUID intents on success
124416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * TODO: Don't wait UUID_INTENT_DELAY to handle the failure case for
124516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * callback and broadcast intents.
124616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     */
124716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    public synchronized boolean fetchRemoteUuids(String address, ParcelUuid uuid,
124816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            IBluetoothCallback callback) {
12491caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
12508c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
12518c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
12521caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
12531caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            return false;
12541caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        }
12551caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
125616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        RemoteService service = new RemoteService(address, uuid);
125716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        if (uuid != null && mUuidCallbackTracker.get(service) != null) {
125816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            // An SDP query for this address & uuid is already in progress
125916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            // Do not add this callback for the uuid
126016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            return false;
126116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
126216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
12631caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        if (mUuidIntentTracker.contains(address)) {
12641caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            // An SDP query for this address is already in progress
126516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            // Add this uuid onto the in-progress SDP query
126616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (uuid != null) {
126716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                mUuidCallbackTracker.put(new RemoteService(address, uuid), callback);
126816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
12691caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            return true;
12701caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        }
12711caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
1272421f0101087bbede1152ccc6d8212f6686a10e54Jaikumar Ganesh        // If the device is already created, we will
1273421f0101087bbede1152ccc6d8212f6686a10e54Jaikumar Ganesh        // do the SDP on the callback of createDeviceNative.
1274421f0101087bbede1152ccc6d8212f6686a10e54Jaikumar Ganesh        boolean ret= createDeviceNative(address);
12751caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
12761caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        mUuidIntentTracker.add(address);
127716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        if (uuid != null) {
127816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            mUuidCallbackTracker.put(new RemoteService(address, uuid), callback);
127916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
12801caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
12811caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        Message message = mHandler.obtainMessage(MESSAGE_UUID_INTENT);
12821caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        message.obj = address;
12831caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        mHandler.sendMessageDelayed(message, UUID_INTENT_DELAY);
12841caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        return ret;
12851caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    }
12861caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
12879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1288d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Gets the rfcomm channel associated with the UUID.
128916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * Pulls records from the cache only.
12909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1291d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * @param address Address of the remote device
1292dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh     * @param uuid ParcelUuid of the service attribute
12939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1294d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * @return rfcomm channel associated with the service attribute
129510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh     *         -1 on error
12969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1297dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh    public int getRemoteServiceChannel(String address, ParcelUuid uuid) {
12989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
12998c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return -1;
13008c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1301005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1302b24e11baac589fe16426f2d243b460ab84991c7bNick Pelly            return BluetoothDevice.ERROR;
13039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
130410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        // Check if we are recovering from a crash.
130510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        if (mDeviceProperties.isEmpty()) {
13069a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            if (mDeviceProperties.updateCache(address) == null)
130710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh                return -1;
130810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        }
130910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
131010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        Map<ParcelUuid, Integer> value = mDeviceServiceChannelCache.get(address);
131110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        if (value != null && value.containsKey(uuid))
131210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            return value.get(uuid);
131310eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        return -1;
13149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean setPin(String address, byte[] pin) {
13179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
13189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
13198c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
13208c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
13219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (pin == null || pin.length <= 0 || pin.length > 16 ||
1322005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            !BluetoothAdapter.checkBluetoothAddress(address)) {
13239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
13249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        address = address.toUpperCase();
13269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
13279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (data == null) {
13289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.w(TAG, "setPin(" + address + ") called but no native data available, " +
13299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                  "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
13309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                  " or by bluez.\n");
13319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
13329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // bluez API wants pin as a string
13349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String pinString;
13359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
13369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pinString = new String(pin, "UTF8");
13379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (UnsupportedEncodingException uee) {
13389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.e(TAG, "UTF8 not supported?!?");
13399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
13409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return setPinNative(address, pinString, data.intValue());
13429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1344b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    public synchronized boolean setPasskey(String address, int passkey) {
1345b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1346b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                                                "Need BLUETOOTH_ADMIN permission");
13478c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
13488c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1349005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (passkey < 0 || passkey > 999999 || !BluetoothAdapter.checkBluetoothAddress(address)) {
1350b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            return false;
1351b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        }
1352b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        address = address.toUpperCase();
1353b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
1354b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        if (data == null) {
1355b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            Log.w(TAG, "setPasskey(" + address + ") called but no native data available, " +
1356b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                  "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
1357b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                  " or by bluez.\n");
1358b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            return false;
1359b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        }
1360b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        return setPasskeyNative(address, passkey, data.intValue());
1361b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    }
1362b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh
1363b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    public synchronized boolean setPairingConfirmation(String address, boolean confirm) {
1364b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1365b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                                                "Need BLUETOOTH_ADMIN permission");
13668c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
13678c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1368b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        address = address.toUpperCase();
1369b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
1370b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        if (data == null) {
1371b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            Log.w(TAG, "setPasskey(" + address + ") called but no native data available, " +
1372b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                  "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
1373b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                  " or by bluez.\n");
1374b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            return false;
1375b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        }
1376b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        return setPairingConfirmationNative(address, confirm, data.intValue());
1377b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    }
1378b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh
1379cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    public synchronized boolean setRemoteOutOfBandData(String address) {
1380cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1381cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh                                                "Need BLUETOOTH_ADMIN permission");
1382cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (!isEnabledInternal()) return false;
1383cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        address = address.toUpperCase();
1384cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
1385cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (data == null) {
1386cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh            Log.w(TAG, "setRemoteOobData(" + address + ") called but no native data available, " +
1387cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh                  "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
1388cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh                  " or by bluez.\n");
1389cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh            return false;
1390cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        }
1391cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
1392cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        Pair<byte[], byte[]> val = mDeviceOobData.get(address);
1393cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        byte[] hash, randomizer;
1394cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (val == null) {
1395cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh            // TODO: check what should be passed in this case.
1396cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh            hash = new byte[16];
1397cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh            randomizer = new byte[16];
1398cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        } else {
1399cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh            hash = val.first;
1400cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh            randomizer = val.second;
1401cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        }
1402cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        return setRemoteOutOfBandDataNative(address, hash, randomizer, data.intValue());
1403cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    }
1404cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
1405b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    public synchronized boolean cancelPairingUserInput(String address) {
14069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
14079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
14088c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
14098c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1410005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
14119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
14129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1413005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        mBondState.setBondState(address, BluetoothDevice.BOND_NONE,
1414397d8f4f4829a45f4fe7a672cc395466bbc0f442Jaikumar Ganesh                BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
14159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        address = address.toUpperCase();
14169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
14179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (data == null) {
1418b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            Log.w(TAG, "cancelUserInputNative(" + address + ") called but no native data " +
1419b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                "available, ignoring. Maybe the PasskeyAgent Request was already cancelled " +
1420b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                "by the remote or by bluez.\n");
14219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
14229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1423b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        return cancelPairingUserInputNative(address, data.intValue());
14249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14268c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh    /*package*/ void updateDeviceServiceChannelCache(String address) {
14279a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        if (DBG) Log.d(TAG, "updateDeviceServiceChannelCache(" + address + ")");
14289a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
142910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        // We are storing the rfcomm channel numbers only for the uuids
143010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        // we are interested in.
14319a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        ParcelUuid[] deviceUuids = getRemoteUuids(address);
143216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
14339a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        ArrayList<ParcelUuid> applicationUuids = new ArrayList<ParcelUuid>();
143416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
143516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        synchronized (this) {
143616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            for (RemoteService service : mUuidCallbackTracker.keySet()) {
143716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (service.address.equals(address)) {
143816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    applicationUuids.add(service.uuid);
143916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                }
144016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
144116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
144210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
14439a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        Map <ParcelUuid, Integer> uuidToChannelMap = new HashMap<ParcelUuid, Integer>();
144416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
144516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        // Retrieve RFCOMM channel for default uuids
144616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        for (ParcelUuid uuid : RFCOMM_UUIDS) {
144710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            if (BluetoothUuid.isUuidPresent(deviceUuids, uuid)) {
14489a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                int channel = getDeviceServiceChannelForUuid(address, uuid);
14499a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                uuidToChannelMap.put(uuid, channel);
14509a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                if (DBG) Log.d(TAG, "\tuuid(system): " + uuid + " " + channel);
145110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            }
145210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        }
145316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        // Retrieve RFCOMM channel for application requested uuids
145416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        for (ParcelUuid uuid : applicationUuids) {
145516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (BluetoothUuid.isUuidPresent(deviceUuids, uuid)) {
14569a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                int channel = getDeviceServiceChannelForUuid(address, uuid);
14579a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                uuidToChannelMap.put(uuid, channel);
14589a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                if (DBG) Log.d(TAG, "\tuuid(application): " + uuid + " " + channel);
145916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
146016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
146116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
146216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        synchronized (this) {
146316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            // Make application callbacks
146416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            for (Iterator<RemoteService> iter = mUuidCallbackTracker.keySet().iterator();
146516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    iter.hasNext();) {
146616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                RemoteService service = iter.next();
146716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (service.address.equals(address)) {
14689a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                    if (uuidToChannelMap.containsKey(service.uuid)) {
14699a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                        int channel = uuidToChannelMap.get(service.uuid);
14709a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
14719a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                        if (DBG) Log.d(TAG, "Making callback for " + service.uuid +
14729a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                                    " with result " + channel);
147316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        IBluetoothCallback callback = mUuidCallbackTracker.get(service);
147416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        if (callback != null) {
147516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                            try {
147616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                                callback.onRfcommChannelFound(channel);
147716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                            } catch (RemoteException e) {Log.e(TAG, "", e);}
147816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        }
147916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
148016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        iter.remove();
148116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    }
148216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                }
148316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
148416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
148516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            // Update cache
14869a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            mDeviceServiceChannelCache.put(address, uuidToChannelMap);
148716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
148810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh    }
148910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
14909a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    private int getDeviceServiceChannelForUuid(String address,
14919a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            ParcelUuid uuid) {
14929a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        return getDeviceServiceChannelNative(getObjectPathFromAddress(address),
14939a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                uuid.toString(), 0x0004);
14949a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    }
14959a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
149624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    /**
149724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     * b is a handle to a Binder instance, so that this service can be notified
149824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     * for Applications that terminate unexpectedly, to clean there service
149924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     * records
150024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     */
150124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    public synchronized int addRfcommServiceRecord(String serviceName, ParcelUuid uuid,
150224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            int channel, IBinder b) {
15038c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
15048c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return -1;
15058c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
150624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (serviceName == null || uuid == null || channel < 1 ||
150724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                channel > BluetoothSocket.MAX_RFCOMM_CHANNEL) {
150824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            return -1;
150924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
151024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (BluetoothUuid.isUuidPresent(BluetoothUuid.RESERVED_UUIDS, uuid)) {
151124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            Log.w(TAG, "Attempted to register a reserved UUID: " + uuid);
151224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            return -1;
151324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
151424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        int handle = addRfcommServiceRecordNative(serviceName,
151524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                uuid.getUuid().getMostSignificantBits(), uuid.getUuid().getLeastSignificantBits(),
151624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                (short)channel);
15179a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        if (DBG) Log.d(TAG, "new handle " + Integer.toHexString(handle));
151824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (handle == -1) {
151924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            return -1;
152024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
152124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
152224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        int pid = Binder.getCallingPid();
152324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        mServiceRecordToPid.put(new Integer(handle), new Integer(pid));
152424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        try {
152524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            b.linkToDeath(new Reaper(handle, pid), 0);
152624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        } catch (RemoteException e) {}
152724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        return handle;
152824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    }
152924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
153024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    public void removeServiceRecord(int handle) {
153124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
153224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                                                "Need BLUETOOTH permission");
153324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        checkAndRemoveRecord(handle, Binder.getCallingPid());
153424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    }
153524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
153624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private synchronized void checkAndRemoveRecord(int handle, int pid) {
153724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        Integer handleInt = new Integer(handle);
153824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        Integer owner = mServiceRecordToPid.get(handleInt);
153924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (owner != null && pid == owner.intValue()) {
15409a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            if (DBG) Log.d(TAG, "Removing service record " +
15419a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                Integer.toHexString(handle) + " for pid " + pid);
154224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            mServiceRecordToPid.remove(handleInt);
154324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            removeServiceRecordNative(handle);
154424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
154524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    }
154624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
154724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private class Reaper implements IBinder.DeathRecipient {
154824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        int pid;
154924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        int handle;
155024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        Reaper(int handle, int pid) {
155124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            this.pid = pid;
155224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            this.handle = handle;
155324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
155424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        public void binderDied() {
155524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            synchronized (BluetoothService.this) {
15569a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                if (DBG) Log.d(TAG, "Tracked app " + pid + " died");
155724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                checkAndRemoveRecord(handle, pid);
155824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            }
155924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
156024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    }
156124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
15629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
15639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
15649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onReceive(Context context, Intent intent) {
15656e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh            if (intent == null) return;
15666e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh
15679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String action = intent.getAction();
15689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
15699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ContentResolver resolver = context.getContentResolver();
15709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Query the airplane mode from Settings.System just to make sure that
15719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // some random app is not sending this intent and disabling bluetooth
15729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                boolean enabled = !isAirplaneModeOn();
15739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // If bluetooth is currently expected to be on, then enable or disable bluetooth
15749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (Settings.Secure.getInt(resolver, Settings.Secure.BLUETOOTH_ON, 0) > 0) {
15759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (enabled) {
1576105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                        enable(false);
15779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } else {
15789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        disable(false);
15799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
15809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
15816e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh            } else if (Intent.ACTION_DOCK_EVENT.equals(action)) {
15826e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                int state = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
15836e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                        Intent.EXTRA_DOCK_STATE_UNDOCKED);
15846e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                if (DBG) Log.v(TAG, "Received ACTION_DOCK_EVENT with State:" + state);
15856e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                if (state == Intent.EXTRA_DOCK_STATE_UNDOCKED) {
15866e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                    mDockAddress = null;
15876e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                    mDockPin = null;
15886e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                } else {
15896e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                    SharedPreferences.Editor editor =
15906e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                        mContext.getSharedPreferences(SHARED_PREFERENCES_NAME,
15916e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                                mContext.MODE_PRIVATE).edit();
15926e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                    editor.putBoolean(SHARED_PREFERENCE_DOCK_ADDRESS + mDockAddress, true);
159366fce5068a8a3aeb28aaf713843891b286a75280Brad Fitzpatrick                    editor.apply();
15946e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                }
15959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
15969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
15979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
15989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15996e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh    private void registerForAirplaneMode(IntentFilter filter) {
160044303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        final ContentResolver resolver = mContext.getContentResolver();
160144303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        final String airplaneModeRadios = Settings.System.getString(resolver,
16029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Settings.System.AIRPLANE_MODE_RADIOS);
160344303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        final String toggleableRadios = Settings.System.getString(resolver,
160444303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey                Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
160544303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey
160644303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        mIsAirplaneSensitive = airplaneModeRadios == null ? true :
160744303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey                airplaneModeRadios.contains(Settings.System.RADIO_BLUETOOTH);
160844303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        mIsAirplaneToggleable = toggleableRadios == null ? false :
160944303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey                toggleableRadios.contains(Settings.System.RADIO_BLUETOOTH);
161044303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey
16119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mIsAirplaneSensitive) {
16126e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh            filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
16139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
16149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
16159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* Returns true if airplane mode is currently on */
16179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final boolean isAirplaneModeOn() {
16189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return Settings.System.getInt(mContext.getContentResolver(),
16199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Settings.System.AIRPLANE_MODE_ON, 0) == 1;
16209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
16219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16221caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    /* Broadcast the Uuid intent */
16231caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    /*package*/ synchronized void sendUuidIntent(String address) {
16246179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh        ParcelUuid[] uuid = getUuidFromCache(address);
16256179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh        Intent intent = new Intent(BluetoothDevice.ACTION_UUID);
16262d3b98d868cda30535505b2a2fba47aa1c9c052bJaikumar Ganesh        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
16276179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh        intent.putExtra(BluetoothDevice.EXTRA_UUID, uuid);
16286179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh        mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
16299a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        mUuidIntentTracker.remove(address);
163016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    }
163116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
163216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    /*package*/ synchronized void makeServiceChannelCallbacks(String address) {
163316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        for (Iterator<RemoteService> iter = mUuidCallbackTracker.keySet().iterator();
163416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                iter.hasNext();) {
163516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            RemoteService service = iter.next();
163616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (service.address.equals(address)) {
16379a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                if (DBG) Log.d(TAG, "Cleaning up failed UUID channel lookup: "
16389a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                    + service.address + " " + service.uuid);
163916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                IBluetoothCallback callback = mUuidCallbackTracker.get(service);
164016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (callback != null) {
164116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    try {
164216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        callback.onRfcommChannelFound(-1);
164316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    } catch (RemoteException e) {Log.e(TAG, "", e);}
164416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                }
164516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
164616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                iter.remove();
164716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
164816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
16491caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    }
16501caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
16519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
16529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
16539a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        dumpBluetoothState(pw);
16549a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        if (mBluetoothState != BluetoothAdapter.STATE_ON) {
1655105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return;
1656105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
1657105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
165824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("mIsAirplaneSensitive = " + mIsAirplaneSensitive);
165944303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        pw.println("mIsAirplaneToggleable = " + mIsAirplaneToggleable);
166024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
166124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("Local address = " + getAddress());
166224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("Local name = " + getName());
166324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("isDiscovering() = " + isDiscovering());
1664105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
166596a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh        mAdapter.getProfileProxy(mContext,
166696a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh                                 mBluetoothProfileServiceListener, BluetoothProfile.HEADSET);
16674ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh        mAdapter.getProfileProxy(mContext,
16684ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                mBluetoothProfileServiceListener, BluetoothProfile.INPUT_DEVICE);
166974ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh        mAdapter.getProfileProxy(mContext,
167074ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                mBluetoothProfileServiceListener, BluetoothProfile.PAN);
1671105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
16729a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        dumpKnownDevices(pw);
16739a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        dumpAclConnectedDevices(pw);
16749a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        dumpHeadsetService(pw);
16754ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh        dumpInputDeviceProfile(pw);
167674ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh        dumpPanProfile(pw);
16779a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        dumpApplicationServiceRecords(pw);
16784ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh    }
16794ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh
16809a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    private void dumpHeadsetService(PrintWriter pw) {
1681105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        pw.println("\n--Headset Service--");
168296a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh        if (mBluetoothHeadset != null) {
1683bb0773fac888c6748cbf778ab5c99c7d0a2c1309Jaikumar Ganesh            List<BluetoothDevice> deviceList = mBluetoothHeadset.getConnectedDevices();
1684bb0773fac888c6748cbf778ab5c99c7d0a2c1309Jaikumar Ganesh            if (deviceList.size() == 0) {
168574ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                pw.println("No headsets connected");
1686bb0773fac888c6748cbf778ab5c99c7d0a2c1309Jaikumar Ganesh            } else {
1687bb0773fac888c6748cbf778ab5c99c7d0a2c1309Jaikumar Ganesh                BluetoothDevice device = deviceList.get(0);
16889a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                pw.println("\ngetConnectedDevices[0] = " + device);
16899a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                dumpHeadsetConnectionState(pw, device);
1690bb0773fac888c6748cbf778ab5c99c7d0a2c1309Jaikumar Ganesh                pw.println("getBatteryUsageHint() = " +
1691bb0773fac888c6748cbf778ab5c99c7d0a2c1309Jaikumar Ganesh                             mBluetoothHeadset.getBatteryUsageHint(device));
169296a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh            }
169396a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh
16945a1e4cf83f5be1b5d79e2643fa791aa269b6a4bcJaikumar Ganesh            deviceList.clear();
16955a1e4cf83f5be1b5d79e2643fa791aa269b6a4bcJaikumar Ganesh            deviceList = mBluetoothHeadset.getDevicesMatchingConnectionStates(new int[] {
169696a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh                     BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED});
169774ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            pw.println("--Connected and Disconnected Headsets");
1698bb0773fac888c6748cbf778ab5c99c7d0a2c1309Jaikumar Ganesh            for (BluetoothDevice device: deviceList) {
169996a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh                pw.println(device);
170096a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh                if (mBluetoothHeadset.isAudioConnected(device)) {
170196a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh                    pw.println("SCO audio connected to device:" + device);
170296a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh                }
170396a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh            }
1704105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
17054ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh        mAdapter.closeProfileProxy(BluetoothProfile.HEADSET, mBluetoothHeadset);
17064ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh    }
17076c901db72dbaf57d8fdf26adae6721de14ecae22Nick Pelly
17084ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh    private void dumpInputDeviceProfile(PrintWriter pw) {
17094ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh        pw.println("\n--Bluetooth Service- Input Device Profile");
17104ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh        if (mInputDevice != null) {
17114ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            List<BluetoothDevice> deviceList = mInputDevice.getConnectedDevices();
17124ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            if (deviceList.size() == 0) {
171374ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                pw.println("No input devices connected");
17144ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            } else {
171574ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                pw.println("Number of connected devices:" + deviceList.size());
17164ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                BluetoothDevice device = deviceList.get(0);
17174ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                pw.println("getConnectedDevices[0] = " + device);
17184ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                pw.println("Priority of Connected device = " + mInputDevice.getPriority(device));
17194ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh
17204ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                switch (mInputDevice.getConnectionState(device)) {
17214ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                    case BluetoothInputDevice.STATE_CONNECTING:
17224ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                        pw.println("getConnectionState() = STATE_CONNECTING");
17234ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                        break;
17244ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                    case BluetoothInputDevice.STATE_CONNECTED:
17254ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                        pw.println("getConnectionState() = STATE_CONNECTED");
17264ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                        break;
17274ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                    case BluetoothInputDevice.STATE_DISCONNECTING:
17284ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                        pw.println("getConnectionState() = STATE_DISCONNECTING");
17294ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                        break;
17304ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                }
17314ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            }
17324ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            deviceList.clear();
17334ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            deviceList = mInputDevice.getDevicesMatchingConnectionStates(new int[] {
17344ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                     BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED});
17354ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            pw.println("--Connected and Disconnected input devices");
17364ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            for (BluetoothDevice device: deviceList) {
17374ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                pw.println(device);
17384ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            }
173924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
17404ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh        mAdapter.closeProfileProxy(BluetoothProfile.INPUT_DEVICE, mBluetoothHeadset);
17419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
17429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
174374ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh    private void dumpPanProfile(PrintWriter pw) {
174474ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh        pw.println("\n--Bluetooth Service- Pan Profile");
174574ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh        if (mPan != null) {
174674ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            List<BluetoothDevice> deviceList = mPan.getConnectedDevices();
174774ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            if (deviceList.size() == 0) {
174874ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                pw.println("No Pan devices connected");
174974ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            } else {
175074ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                pw.println("Number of connected devices:" + deviceList.size());
175174ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                BluetoothDevice device = deviceList.get(0);
175274ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                pw.println("getConnectedDevices[0] = " + device);
175374ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh
175474ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                switch (mPan.getConnectionState(device)) {
175574ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                    case BluetoothInputDevice.STATE_CONNECTING:
175674ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                        pw.println("getConnectionState() = STATE_CONNECTING");
175774ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                        break;
175874ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                    case BluetoothInputDevice.STATE_CONNECTED:
175974ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                        pw.println("getConnectionState() = STATE_CONNECTED");
176074ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                        break;
176174ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                    case BluetoothInputDevice.STATE_DISCONNECTING:
176274ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                        pw.println("getConnectionState() = STATE_DISCONNECTING");
176374ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                        break;
176474ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                }
176574ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            }
176674ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            deviceList.clear();
176774ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            deviceList = mPan.getDevicesMatchingConnectionStates(new int[] {
176874ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                     BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED});
176974ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            pw.println("--Connected and Disconnected Pan devices");
177074ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            for (BluetoothDevice device: deviceList) {
177174ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                pw.println(device);
177274ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            }
177374ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh        }
17749a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    }
17759a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
17769a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    private void dumpHeadsetConnectionState(PrintWriter pw,
17779a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            BluetoothDevice device) {
17789a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        switch (mBluetoothHeadset.getConnectionState(device)) {
17799a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            case BluetoothHeadset.STATE_CONNECTING:
17809a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                pw.println("getConnectionState() = STATE_CONNECTING");
17819a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                break;
17829a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            case BluetoothHeadset.STATE_CONNECTED:
17839a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                pw.println("getConnectionState() = STATE_CONNECTED");
17849a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                break;
17859a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            case BluetoothHeadset.STATE_DISCONNECTING:
17869a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                pw.println("getConnectionState() = STATE_DISCONNECTING");
17879a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                break;
17889a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            case BluetoothHeadset.STATE_AUDIO_CONNECTED:
17899a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                pw.println("getConnectionState() = STATE_AUDIO_CONNECTED");
17909a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                break;
17919a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        }
17929a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    }
17939a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
17949a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    private void dumpApplicationServiceRecords(PrintWriter pw) {
17959a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        pw.println("\n--Application Service Records--");
17969a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        for (Integer handle : mServiceRecordToPid.keySet()) {
17979a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            Integer pid = mServiceRecordToPid.get(handle);
17989a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            pw.println("\tpid " + pid + " handle " + Integer.toHexString(handle));
17999a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        }
180074ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh        mAdapter.closeProfileProxy(BluetoothProfile.PAN, mBluetoothHeadset);
180174ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh    }
180274ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh
18039a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    private void dumpAclConnectedDevices(PrintWriter pw) {
18049a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        String[] devicesObjectPath = getKnownDevices();
18059a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        pw.println("\n--ACL connected devices--");
18069a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        if (devicesObjectPath != null) {
18079a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            for (String device : devicesObjectPath) {
18089a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                pw.println(getAddressFromObjectPath(device));
18099a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            }
18109a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        }
18119a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    }
18129a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
18139a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    private void dumpKnownDevices(PrintWriter pw) {
18149a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        pw.println("\n--Known devices--");
18159a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        for (String address : mDeviceProperties.keySet()) {
18169a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            int bondState = mBondState.getBondState(address);
18179a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            pw.printf("%s %10s (%d) %s\n", address,
18189a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                       toBondStateString(bondState),
18199a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                       mBondState.getAttempt(address),
18209a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                       getRemoteName(address));
18219a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
18229a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            Map<ParcelUuid, Integer> uuidChannels = mDeviceServiceChannelCache.get(address);
18239a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            if (uuidChannels == null) {
18249a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                pw.println("\tuuids = null");
18259a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            } else {
18269a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                for (ParcelUuid uuid : uuidChannels.keySet()) {
18279a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                    Integer channel = uuidChannels.get(uuid);
18289a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                    if (channel == null) {
18299a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                        pw.println("\t" + uuid);
18309a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                    } else {
18319a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                        pw.println("\t" + uuid + " RFCOMM channel = " + channel);
18329a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                    }
18339a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                }
18349a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            }
18359a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            for (RemoteService service : mUuidCallbackTracker.keySet()) {
18369a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                if (service.address.equals(address)) {
18379a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                    pw.println("\tPENDING CALLBACK: " + service.uuid);
18389a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                }
18399a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            }
18409a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        }
18419a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    }
18429a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
18439a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    private void dumpBluetoothState(PrintWriter pw) {
18449a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        switch(mBluetoothState) {
18459a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        case BluetoothAdapter.STATE_OFF:
18469a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            pw.println("Bluetooth OFF\n");
18479a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            break;
18489a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        case BluetoothAdapter.STATE_TURNING_ON:
18499a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            pw.println("Bluetooth TURNING ON\n");
18509a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            break;
18519a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        case BluetoothAdapter.STATE_TURNING_OFF:
18529a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            pw.println("Bluetooth TURNING OFF\n");
18539a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            break;
18549a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        case BluetoothAdapter.STATE_ON:
18559a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            pw.println("Bluetooth ON\n");
18569a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            break;
18579a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        default:
18589a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            pw.println("Bluetooth UNKNOWN STATE " + mBluetoothState);
18599a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        }
18609a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    }
18619a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
186296a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh    private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
186396a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh        new BluetoothProfile.ServiceListener() {
186496a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh        public void onServiceConnected(int profile, BluetoothProfile proxy) {
18654ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            if (profile == BluetoothProfile.HEADSET) {
18664ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                mBluetoothHeadset = (BluetoothHeadset) proxy;
18674ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            } else if (profile == BluetoothProfile.INPUT_DEVICE) {
18684ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                mInputDevice = (BluetoothInputDevice) proxy;
186974ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            } else if (profile == BluetoothProfile.PAN) {
187074ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                mPan = (BluetoothPan) proxy;
18714ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            }
18724ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh        }
187396a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh        public void onServiceDisconnected(int profile) {
18744ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            if (profile == BluetoothProfile.HEADSET) {
18754ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                mBluetoothHeadset = null;
18764ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            } else if (profile == BluetoothProfile.INPUT_DEVICE) {
18774ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                mInputDevice = null;
187874ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            } else if (profile == BluetoothProfile.PAN) {
187974ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                mPan = null;
18804ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            }
188196a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh        }
188296a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh    };
188396a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh
1884d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ static int bluezStringToScanMode(boolean pairable, boolean discoverable) {
1885d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (pairable && discoverable)
1886bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            return BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE;
1887d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        else if (pairable && !discoverable)
1888bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            return BluetoothAdapter.SCAN_MODE_CONNECTABLE;
1889d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        else
1890bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            return BluetoothAdapter.SCAN_MODE_NONE;
18919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
18929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* package */ static String scanModeToBluezString(int mode) {
18949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        switch (mode) {
1895bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        case BluetoothAdapter.SCAN_MODE_NONE:
18969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "off";
1897bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
18989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "connectable";
1899bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
19009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "discoverable";
19019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
19029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return null;
19039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
19049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1905d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /*package*/ String getAddressFromObjectPath(String objectPath) {
19069a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        String adapterObjectPath = mAdapterProperties.getObjectPath();
1907d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (adapterObjectPath == null || objectPath == null) {
1908f51eadaf1f83abfe16a609a4ded6d789494689b2Jake Hamby            Log.e(TAG, "getAddressFromObjectPath: AdapterObjectPath:" + adapterObjectPath +
1909d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                    "  or deviceObjectPath:" + objectPath + " is null");
1910d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return null;
1911d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
1912d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (!objectPath.startsWith(adapterObjectPath)) {
1913f51eadaf1f83abfe16a609a4ded6d789494689b2Jake Hamby            Log.e(TAG, "getAddressFromObjectPath: AdapterObjectPath:" + adapterObjectPath +
1914d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                    "  is not a prefix of deviceObjectPath:" + objectPath +
1915d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                    "bluetoothd crashed ?");
1916d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return null;
1917d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
1918d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String address = objectPath.substring(adapterObjectPath.length());
1919d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (address != null) return address.replace('_', ':');
1920d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1921d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        Log.e(TAG, "getAddressFromObjectPath: Address being returned is null");
1922d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return null;
1923d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
1924d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1925d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /*package*/ String getObjectPathFromAddress(String address) {
19269a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        String path = mAdapterProperties.getObjectPath();
1927d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (path == null) {
1928d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            Log.e(TAG, "Error: Object Path is null");
1929d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return null;
1930d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
1931d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        path = path + address.replace(":", "_");
1932d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return path;
1933d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
1934d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1935b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh    /*package */ void setLinkTimeout(String address, int num_slots) {
1936b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh        String path = getObjectPathFromAddress(address);
1937b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh        boolean result = setLinkTimeoutNative(path, num_slots);
1938b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh
19399a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        if (!result) Log.d(TAG, "Set Link Timeout to " + num_slots + " slots failed");
1940b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh    }
1941b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh
194230b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    /**** Handlers for PAN  Profile ****/
19436003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh    // TODO: This needs to be converted to a state machine.
194430b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
19456003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh    public boolean isTetheringOn() {
194630b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
19476003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        synchronized (mBluetoothPanProfileHandler) {
19486003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh            return mBluetoothPanProfileHandler.isTetheringOn();
19496003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        }
195030b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
195130b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
19526003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh    /*package*/boolean allowIncomingTethering() {
19536003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        synchronized (mBluetoothPanProfileHandler) {
19546003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh            return mBluetoothPanProfileHandler.allowIncomingTethering();
19556003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        }
195630b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
195730b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
19586003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh    public void setBluetoothTethering(boolean value) {
195930b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
19606003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        synchronized (mBluetoothPanProfileHandler) {
19616003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh            mBluetoothPanProfileHandler.setBluetoothTethering(value);
19626003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        }
196330b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
196430b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
19656003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh    public int getPanDeviceConnectionState(BluetoothDevice device) {
196630b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
19676003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        synchronized (mBluetoothPanProfileHandler) {
19686003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh            return mBluetoothPanProfileHandler.getPanDeviceConnectionState(device);
19696003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        }
197030b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
197130b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
19726003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh    public boolean connectPanDevice(BluetoothDevice device) {
197330b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
197430b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh            "Need BLUETOOTH_ADMIN permission");
19756003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        synchronized (mBluetoothPanProfileHandler) {
19766003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh            return mBluetoothPanProfileHandler.connectPanDevice(device);
19776003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        }
197830b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
197930b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
19806003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh    public List<BluetoothDevice> getConnectedPanDevices() {
198130b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
19826003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        synchronized (mBluetoothPanProfileHandler) {
19836003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh            return mBluetoothPanProfileHandler.getConnectedPanDevices();
19846003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        }
198530b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
198630b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
19876003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh    public List<BluetoothDevice> getPanDevicesMatchingConnectionStates(
198874ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            int[] states) {
198974ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
19906003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        synchronized (mBluetoothPanProfileHandler) {
19916003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh            return mBluetoothPanProfileHandler.getPanDevicesMatchingConnectionStates(states);
19926003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        }
199374ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh    }
199474ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh
19956003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh    public boolean disconnectPanDevice(BluetoothDevice device) {
199630b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
199730b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh            "Need BLUETOOTH_ADMIN permission");
19986003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        synchronized (mBluetoothPanProfileHandler) {
19996003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh            return mBluetoothPanProfileHandler.disconnectPanDevice(device);
20006003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        }
200130b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
200230b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
20036003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh    /*package*/void handlePanDeviceStateChange(BluetoothDevice device,
200430b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh                                                             String iface,
200530b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh                                                             int state,
200630b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh                                                             int role) {
20076003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        synchronized (mBluetoothPanProfileHandler) {
20086003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh            mBluetoothPanProfileHandler.handlePanDeviceStateChange(device, iface, state, role);
20096003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        }
201030b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
201130b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
20126003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh    /*package*/void handlePanDeviceStateChange(BluetoothDevice device,
201330b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh                                                             int state, int role) {
20146003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        synchronized (mBluetoothPanProfileHandler) {
20156003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh            mBluetoothPanProfileHandler.handlePanDeviceStateChange(device, null, state, role);
20166003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        }
201730b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
201830b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
201930b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    /**** Handlers for Input Device Profile ****/
20206003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh    // This needs to be converted to state machine
202130b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
20226003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh    public boolean connectInputDevice(BluetoothDevice device) {
202330b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
202430b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh                                                "Need BLUETOOTH_ADMIN permission");
202530b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        BluetoothDeviceProfileState state = mDeviceProfileState.get(device.getAddress());
20266003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        synchronized (mBluetoothInputProfileHandler) {
20276003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh            return mBluetoothInputProfileHandler.connectInputDevice(device, state);
20286003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        }
202930b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
203030b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
20316003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh    public boolean connectInputDeviceInternal(BluetoothDevice device) {
20326003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        synchronized (mBluetoothInputProfileHandler) {
20336003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh            return mBluetoothInputProfileHandler.connectInputDeviceInternal(device);
20346003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        }
203530b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
203630b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
20376003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh    public boolean disconnectInputDevice(BluetoothDevice device) {
203830b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
203930b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh                                                "Need BLUETOOTH_ADMIN permission");
204030b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        BluetoothDeviceProfileState state = mDeviceProfileState.get(device.getAddress());
20416003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        synchronized (mBluetoothInputProfileHandler) {
20426003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh            return mBluetoothInputProfileHandler.disconnectInputDevice(device, state);
20436003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        }
204430b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
204530b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
20466003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh    public boolean disconnectInputDeviceInternal(BluetoothDevice device) {
20476003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        synchronized (mBluetoothInputProfileHandler) {
20486003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh            return mBluetoothInputProfileHandler.disconnectInputDeviceInternal(device);
20496003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        }
205030b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
205130b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
20526003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh    public int getInputDeviceConnectionState(BluetoothDevice device) {
205330b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
20546003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        synchronized (mBluetoothInputProfileHandler) {
20556003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh            return mBluetoothInputProfileHandler.getInputDeviceConnectionState(device);
20566003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        }
205730b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
205830b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
20596003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh    public List<BluetoothDevice> getConnectedInputDevices() {
206030b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
20616003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        synchronized (mBluetoothInputProfileHandler) {
20626003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh            return mBluetoothInputProfileHandler.getConnectedInputDevices();
20636003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        }
206430b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
206530b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
20666003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh    public List<BluetoothDevice> getInputDevicesMatchingConnectionStates(
20674ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            int[] states) {
20684ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
20696003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        synchronized (mBluetoothInputProfileHandler) {
20706003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh            return mBluetoothInputProfileHandler.getInputDevicesMatchingConnectionStates(states);
20716003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        }
20724ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh    }
20734ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh
20744ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh
20756003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh    public int getInputDevicePriority(BluetoothDevice device) {
207630b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
20776003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        synchronized (mBluetoothInputProfileHandler) {
20786003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh            return mBluetoothInputProfileHandler.getInputDevicePriority(device);
20796003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        }
208030b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
208130b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
20826003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh    public boolean setInputDevicePriority(BluetoothDevice device, int priority) {
208330b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
208430b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh                                                "Need BLUETOOTH_ADMIN permission");
20856003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        synchronized (mBluetoothInputProfileHandler) {
20866003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh            return mBluetoothInputProfileHandler.setInputDevicePriority(device, priority);
20876003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        }
208830b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
208930b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
2090a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    public boolean allowIncomingHidConnect(BluetoothDevice device, boolean allow) {
2091a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
2092a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                                                "Need BLUETOOTH_ADMIN permission");
2093a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        String address = device.getAddress();
2094a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
2095a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            return false;
2096a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        }
2097a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie
2098a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        Integer data = getAuthorizationAgentRequestData(address);
2099a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        if (data == null) {
2100a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            Log.w(TAG, "allowIncomingHidConnect(" + device +
2101a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                  ") called but no native data available");
2102a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            return false;
2103a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        }
2104a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        if (DBG) log("allowIncomingHidConnect: " + device + " : " + allow + " : " + data);
2105a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        return setAuthorizationNative(address, allow, data.intValue());
2106a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    }
2107a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie
21086003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh    /*package*/List<BluetoothDevice> lookupInputDevicesMatchingStates(int[] states) {
21096003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        synchronized (mBluetoothInputProfileHandler) {
21106003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh            return mBluetoothInputProfileHandler.lookupInputDevicesMatchingStates(states);
21116003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        }
211230b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
211330b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
21146003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh    /*package*/void handleInputDevicePropertyChange(String address, boolean connected) {
21156003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        synchronized (mBluetoothInputProfileHandler) {
21166003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh            mBluetoothInputProfileHandler.handleInputDevicePropertyChange(address, connected);
21176003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        }
211830b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
211930b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
21202ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /**** Handlers for Health Device Profile ****/
21212ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    // TODO: All these need to be converted to a state machine.
21222ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
2123fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh    public boolean registerAppConfiguration(BluetoothHealthAppConfiguration config,
2124fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh                                            IBluetoothHealthCallback callback) {
21252ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
21262ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                "Need BLUETOOTH permission");
21272ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        synchronized (mBluetoothHealthProfileHandler) {
2128fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh                return mBluetoothHealthProfileHandler.registerAppConfiguration(config, callback);
21292ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        }
21302ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
21312ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
21322ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public boolean unregisterAppConfiguration(BluetoothHealthAppConfiguration config) {
21332ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
21342ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                "Need BLUETOOTH permission");
21352ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        synchronized (mBluetoothHealthProfileHandler) {
21362ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                return mBluetoothHealthProfileHandler.unregisterAppConfiguration(config);
21372ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        }
21382ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
21392ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
21402ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
21412ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public boolean connectChannelToSource(BluetoothDevice device,
21422ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            BluetoothHealthAppConfiguration config) {
21432ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
21442ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                "Need BLUETOOTH permission");
21452ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        synchronized (mBluetoothHealthProfileHandler) {
21462ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            return mBluetoothHealthProfileHandler.connectChannelToSource(device,
21472ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                    config);
21482ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        }
21492ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
21502ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
21512ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public boolean connectChannelToSink(BluetoothDevice device,
21522ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            BluetoothHealthAppConfiguration config, int channelType) {
21532ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
21542ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                                                "Need BLUETOOTH permission");
21552ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        synchronized (mBluetoothHealthProfileHandler) {
21562ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            return mBluetoothHealthProfileHandler.connectChannel(device, config,
21572ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                    channelType);
21582ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        }
21592ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
21602ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
21612ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public boolean disconnectChannel(BluetoothDevice device,
21622ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            BluetoothHealthAppConfiguration config, ParcelFileDescriptor fd) {
21632ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
21642ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                "Need BLUETOOTH permission");
21652ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        synchronized (mBluetoothHealthProfileHandler) {
21662ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            return mBluetoothHealthProfileHandler.disconnectChannel(device, config, fd);
21672ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        }
21682ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
21692ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
21702ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public ParcelFileDescriptor getMainChannelFd(BluetoothDevice device,
21712ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            BluetoothHealthAppConfiguration config) {
21722ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
21732ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                "Need BLUETOOTH permission");
21742ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        synchronized (mBluetoothHealthProfileHandler) {
21752ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            return mBluetoothHealthProfileHandler.getMainChannelFd(device, config);
21762ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        }
21772ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
21782ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
21792ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /*package*/ void onHealthDevicePropertyChanged(String devicePath,
21802ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            String channelPath) {
21812ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        synchronized (mBluetoothHealthProfileHandler) {
21822ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            mBluetoothHealthProfileHandler.onHealthDevicePropertyChanged(devicePath,
21832ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                    channelPath);
21842ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        }
21852ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
21862ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
21872ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /*package*/ void onHealthDeviceChannelChanged(String devicePath,
21882ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            String channelPath, boolean exists) {
21892ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        synchronized(mBluetoothHealthProfileHandler) {
21902ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            mBluetoothHealthProfileHandler.onHealthDeviceChannelChanged(devicePath,
21912ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                    channelPath, exists);
21922ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        }
21932ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
21942ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
21952ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public int getHealthDeviceConnectionState(BluetoothDevice device) {
21962ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
21972ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                "Need BLUETOOTH permission");
21982ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        synchronized (mBluetoothHealthProfileHandler) {
21992ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            return mBluetoothHealthProfileHandler.getHealthDeviceConnectionState(device);
22002ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        }
22012ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
22022ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
22032ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public List<BluetoothDevice> getConnectedHealthDevices() {
22042ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
22052ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                "Need BLUETOOTH permission");
22062ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        synchronized (mBluetoothHealthProfileHandler) {
22072ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            return mBluetoothHealthProfileHandler.getConnectedHealthDevices();
22082ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        }
22092ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
22102ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
22112ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public List<BluetoothDevice> getHealthDevicesMatchingConnectionStates(
22122ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            int[] states) {
22132ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
22142ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                "Need BLUETOOTH permission");
22152ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        synchronized (mBluetoothHealthProfileHandler) {
22162ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            return mBluetoothHealthProfileHandler.
22172ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                    getHealthDevicesMatchingConnectionStates(states);
22182ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        }
22192ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
22202ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
2221a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    /*package*/boolean notifyIncomingHidConnection(String address) {
2222a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
2223a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        if (state == null) {
2224a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            return false;
2225a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        }
2226a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        Message msg = new Message();
2227a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        msg.what = BluetoothDeviceProfileState.CONNECT_HID_INCOMING;
2228a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        state.sendMessage(msg);
2229a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        return true;
2230a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    }
2231a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie
22329b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public boolean connectHeadset(String address) {
223396a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh        if (getBondState(address) != BluetoothDevice.BOND_BONDED) return false;
223496a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh
2235f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
22369b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (state != null) {
2237f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            Message msg = new Message();
2238f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.arg1 = BluetoothDeviceProfileState.CONNECT_HFP_OUTGOING;
2239f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.obj = state;
2240f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            mHfpProfileState.sendMessage(msg);
2241f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            return true;
22429b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
22439b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        return false;
22449b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
22459b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
22469b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public boolean disconnectHeadset(String address) {
224796a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh        if (getBondState(address) != BluetoothDevice.BOND_BONDED) return false;
224896a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh
2249f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
22509b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (state != null) {
2251f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            Message msg = new Message();
2252f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.arg1 = BluetoothDeviceProfileState.DISCONNECT_HFP_OUTGOING;
2253f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.obj = state;
2254f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            mHfpProfileState.sendMessage(msg);
22559b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            return true;
22569b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
22579b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        return false;
22589b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
22599b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
22609b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public boolean connectSink(String address) {
226196a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh        if (getBondState(address) != BluetoothDevice.BOND_BONDED) return false;
226296a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh
2263f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
22649b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (state != null) {
2265f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            Message msg = new Message();
2266f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.arg1 = BluetoothDeviceProfileState.CONNECT_A2DP_OUTGOING;
2267f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.obj = state;
2268f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            mA2dpProfileState.sendMessage(msg);
2269f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            return true;
22709b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
22719b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        return false;
22729b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
22739b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
22749b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public boolean disconnectSink(String address) {
227596a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh        if (getBondState(address) != BluetoothDevice.BOND_BONDED) return false;
227696a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh
2277f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
22789b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (state != null) {
2279f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            Message msg = new Message();
2280f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.arg1 = BluetoothDeviceProfileState.DISCONNECT_A2DP_OUTGOING;
2281f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.obj = state;
2282f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            mA2dpProfileState.sendMessage(msg);
22839b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            return true;
22849b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
22859b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        return false;
22869b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
22879b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
22889a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    BluetoothDeviceProfileState addProfileState(String address) {
2289f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
22909b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (state != null) return state;
22919b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
2292f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        state = new BluetoothDeviceProfileState(mContext, address, this, mA2dpService);
2293f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        mDeviceProfileState.put(address, state);
22949b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        state.start();
22959b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        return state;
22969b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
22979b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
22989a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    void removeProfileState(String address) {
2299f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        mDeviceProfileState.remove(address);
23009b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
23019b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
23029a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    synchronized String[] getKnownDevices() {
23039a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        String[] bonds = null;
23049a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        String val = getProperty("Devices");
23059a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        if (val != null) {
23069a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            bonds = val.split(",");
23079a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        }
23089a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        return bonds;
23099a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    }
23109a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
23119b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    private void initProfileState() {
23129a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        String[] bonds = null;
23139a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        String val = mAdapterProperties.getProperty("Devices");
23149b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (val != null) {
23159b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            bonds = val.split(",");
23169b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
23179b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (bonds == null) {
23189b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            return;
23199b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
23209b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        for (String path : bonds) {
23219b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            String address = getAddressFromObjectPath(path);
2322f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            BluetoothDeviceProfileState state = addProfileState(address);
23239a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        }
23249a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    }
23259a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
23269a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    private void autoConnect() {
23279a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        String[] bonds = getKnownDevices();
23289a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        if (bonds == null) {
23299a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            return;
23309a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        }
23319a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        for (String path : bonds) {
23329a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            String address = getAddressFromObjectPath(path);
23339a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
23349a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            if (state != null) {
23359a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                Message msg = new Message();
23369a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                msg.what = BluetoothDeviceProfileState.AUTO_CONNECT_PROFILES;
23379a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                state.sendMessage(msg);
23389a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            }
23399b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
23409b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
23419b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
23429b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public boolean notifyIncomingConnection(String address) {
2343f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        BluetoothDeviceProfileState state =
2344f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh             mDeviceProfileState.get(address);
23459b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (state != null) {
23469b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            Message msg = new Message();
2347f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.what = BluetoothDeviceProfileState.CONNECT_HFP_INCOMING;
23489b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            state.sendMessage(msg);
23499b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            return true;
23509b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
23519b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        return false;
23529b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
23539b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
23549b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    /*package*/ boolean notifyIncomingA2dpConnection(String address) {
2355f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh       BluetoothDeviceProfileState state =
2356f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            mDeviceProfileState.get(address);
23579b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh       if (state != null) {
23589b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh           Message msg = new Message();
2359f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh           msg.what = BluetoothDeviceProfileState.CONNECT_A2DP_INCOMING;
23609b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh           state.sendMessage(msg);
23619b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh           return true;
23629b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh       }
23639b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh       return false;
23649b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
23659b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
23669b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    /*package*/ void setA2dpService(BluetoothA2dpService a2dpService) {
23679b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        mA2dpService = a2dpService;
23689b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
23699b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
2370a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    /*package*/ Integer getAuthorizationAgentRequestData(String address) {
2371a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        Integer data = mEventLoop.getAuthorizationAgentRequestData().remove(address);
2372a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        return data;
2373a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    }
2374a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie
237570a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh    public void sendProfileStateMessage(int profile, int cmd) {
237670a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh        Message msg = new Message();
237770a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh        msg.what = cmd;
237870a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh        if (profile == BluetoothProfileState.HFP) {
237970a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh            mHfpProfileState.sendMessage(msg);
238070a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh        } else if (profile == BluetoothProfileState.A2DP) {
238170a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh            mA2dpProfileState.sendMessage(msg);
238270a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh        }
238370a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh    }
238470a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh
2385c53cab20b225ba69057441ecb06db6478ab8ff9bJaikumar Ganesh    public int getAdapterConnectionState() {
2386c53cab20b225ba69057441ecb06db6478ab8ff9bJaikumar Ganesh        return mAdapterConnectionState;
2387c53cab20b225ba69057441ecb06db6478ab8ff9bJaikumar Ganesh    }
2388c53cab20b225ba69057441ecb06db6478ab8ff9bJaikumar Ganesh
2389a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh    public synchronized void sendConnectionStateChange(BluetoothDevice device, int state,
2390a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh                                                        int prevState) {
23919a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        // Since this is a binder call check if Bluetooth is on still
23929a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        if (mBluetoothState == BluetoothAdapter.STATE_OFF) return;
23939a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
23949a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        if (updateCountersAndCheckForConnectionStateChange(state, prevState)) {
23959a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            if (!validateProfileConnectionState(state) ||
23969a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                    !validateProfileConnectionState(prevState)) {
23979a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                // Previously, an invalid state was broadcast anyway,
23989a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                // with the invalid state converted to -1 in the intent.
23999a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                // Better to log an error and not send an intent with
24009a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                // invalid contents or set mAdapterConnectionState to -1.
24019a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                Log.e(TAG, "Error in sendConnectionStateChange: "
24029a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                        + "prevState " + prevState + " state " + state);
24039a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                return;
24049a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            }
2405c53cab20b225ba69057441ecb06db6478ab8ff9bJaikumar Ganesh
2406c53cab20b225ba69057441ecb06db6478ab8ff9bJaikumar Ganesh            mAdapterConnectionState = state;
2407c53cab20b225ba69057441ecb06db6478ab8ff9bJaikumar Ganesh
2408a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh            Intent intent = new Intent(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
2409a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh            intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
24109a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            intent.putExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE,
24119a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                    convertToAdapterState(state));
24129a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_CONNECTION_STATE,
24139a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                    convertToAdapterState(prevState));
241460b4d2a2bd232a7116fd037501cac704f328c0a1Jaikumar Ganesh            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
2415a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh            mContext.sendBroadcast(intent, BLUETOOTH_PERM);
24169a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            Log.d(TAG, "CONNECTION_STATE_CHANGE: " + device + ": "
24179a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                    + prevState + " -> " + state);
2418a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh        }
2419a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh    }
2420a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh
24219a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    private boolean validateProfileConnectionState(int state) {
24229a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        return (state == BluetoothProfile.STATE_DISCONNECTED ||
24239a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                state == BluetoothProfile.STATE_CONNECTING ||
24249a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                state == BluetoothProfile.STATE_CONNECTED ||
24259a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                state == BluetoothProfile.STATE_DISCONNECTING);
24269a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    }
24279a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
24289a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    private int convertToAdapterState(int state) {
2429a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh        switch (state) {
24309a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            case BluetoothProfile.STATE_DISCONNECTED:
24319a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                return BluetoothAdapter.STATE_DISCONNECTED;
24329a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            case BluetoothProfile.STATE_DISCONNECTING:
24339a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                return BluetoothAdapter.STATE_DISCONNECTING;
24349a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            case BluetoothProfile.STATE_CONNECTED:
24359a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                return BluetoothAdapter.STATE_CONNECTED;
2436a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh            case BluetoothProfile.STATE_CONNECTING:
2437a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh                return BluetoothAdapter.STATE_CONNECTING;
24389a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        }
24399a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        Log.e(TAG, "Error in convertToAdapterState");
24409a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        return -1;
24419a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    }
24429a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
24439a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    private boolean updateCountersAndCheckForConnectionStateChange(int state, int prevState) {
24449a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        switch (prevState) {
24459a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            case BluetoothProfile.STATE_CONNECTING:
24469a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                mProfilesConnecting--;
24479a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                break;
24489a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
2449a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh            case BluetoothProfile.STATE_CONNECTED:
24509a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                mProfilesConnected--;
24519a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                break;
24529a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
2453a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh            case BluetoothProfile.STATE_DISCONNECTING:
24549a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                mProfilesDisconnecting--;
24559a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                break;
2456a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh        }
2457a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh
2458a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh        switch (state) {
2459a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh            case BluetoothProfile.STATE_CONNECTING:
2460a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh                mProfilesConnecting++;
24619a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                return (mProfilesConnected == 0 && mProfilesConnecting == 1);
2462a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh
2463a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh            case BluetoothProfile.STATE_CONNECTED:
2464a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh                mProfilesConnected++;
24659a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                return (mProfilesConnected == 1);
2466a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh
2467a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh            case BluetoothProfile.STATE_DISCONNECTING:
2468a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh                mProfilesDisconnecting++;
24699a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                return (mProfilesConnected == 0 && mProfilesDisconnecting == 1);
2470a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh
2471a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh            case BluetoothProfile.STATE_DISCONNECTED:
24729a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                return (mProfilesConnected == 0 && mProfilesConnecting == 0);
2473a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh
24749a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            default:
24759a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                return true;
2476a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh        }
24779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2478d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
2479a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    private void createIncomingConnectionStateFile() {
2480a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        File f = new File(INCOMING_CONNECTION_FILE);
2481a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        if (!f.exists()) {
2482a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            try {
2483a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                f.createNewFile();
2484a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            } catch (IOException e) {
2485a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                Log.e(TAG, "IOException: cannot create file");
2486a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            }
2487a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        }
2488a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    }
2489a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie
2490a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    /** @hide */
2491a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    public Pair<Integer, String> getIncomingState(String address) {
2492a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        if (mIncomingConnections.isEmpty()) {
2493a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            createIncomingConnectionStateFile();
2494a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            readIncomingConnectionState();
2495a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        }
2496a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        return mIncomingConnections.get(address);
2497a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    }
2498a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie
2499a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    private void readIncomingConnectionState() {
2500a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        synchronized(mIncomingConnections) {
2501a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            FileInputStream fstream = null;
2502a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            try {
2503a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie              fstream = new FileInputStream(INCOMING_CONNECTION_FILE);
2504a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie              DataInputStream in = new DataInputStream(fstream);
2505a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie              BufferedReader file = new BufferedReader(new InputStreamReader(in));
2506a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie              String line;
2507a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie              while((line = file.readLine()) != null) {
2508a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                  line = line.trim();
2509a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                  if (line.length() == 0) continue;
2510a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                  String[] value = line.split(",");
2511a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                  if (value != null && value.length == 3) {
2512a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                      Integer val1 = Integer.parseInt(value[1]);
2513a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                      Pair<Integer, String> val = new Pair(val1, value[2]);
2514a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                      mIncomingConnections.put(value[0], val);
2515a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                  }
2516a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie              }
2517a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            } catch (FileNotFoundException e) {
2518a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                log("FileNotFoundException: readIncomingConnectionState" + e.toString());
2519a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            } catch (IOException e) {
2520a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                log("IOException: readIncomingConnectionState" + e.toString());
2521a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            } finally {
2522a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                if (fstream != null) {
2523a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                    try {
2524a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                        fstream.close();
2525a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                    } catch (IOException e) {
2526a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                        // Ignore
2527a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                    }
2528a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                }
2529a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            }
2530a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        }
2531a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    }
2532a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie
2533a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    private void truncateIncomingConnectionFile() {
2534a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        RandomAccessFile r = null;
2535a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        try {
2536a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            r = new RandomAccessFile(INCOMING_CONNECTION_FILE, "rw");
2537a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            r.setLength(0);
2538a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        } catch (FileNotFoundException e) {
2539a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            log("FileNotFoundException: truncateIncomingConnectionState" + e.toString());
2540a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        } catch (IOException e) {
2541a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            log("IOException: truncateIncomingConnectionState" + e.toString());
2542a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        } finally {
2543a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            if (r != null) {
2544a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                try {
2545a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                    r.close();
2546a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                } catch (IOException e) {
2547a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                    // ignore
2548a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                 }
2549a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            }
2550a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        }
2551a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    }
2552a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie
2553a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    /** @hide */
2554a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    public void writeIncomingConnectionState(String address, Pair<Integer, String> data) {
2555a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        synchronized(mIncomingConnections) {
2556a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            mIncomingConnections.put(address, data);
2557a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie
2558a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            truncateIncomingConnectionFile();
2559a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            BufferedWriter out = null;
2560a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            StringBuilder value = new StringBuilder();
2561a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            try {
2562a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                out = new BufferedWriter(new FileWriter(INCOMING_CONNECTION_FILE, true));
2563a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                for (String devAddress: mIncomingConnections.keySet()) {
2564a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                  Pair<Integer, String> val = mIncomingConnections.get(devAddress);
2565a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                  value.append(devAddress);
2566a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                  value.append(",");
2567a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                  value.append(val.first.toString());
2568a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                  value.append(",");
2569a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                  value.append(val.second);
2570a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                  value.append("\n");
2571a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                }
2572a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                out.write(value.toString());
2573a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            } catch (FileNotFoundException e) {
2574a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                log("FileNotFoundException: writeIncomingConnectionState" + e.toString());
2575a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            } catch (IOException e) {
2576a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                log("IOException: writeIncomingConnectionState" + e.toString());
2577a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            } finally {
2578a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                if (out != null) {
2579a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                    try {
2580a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                        out.close();
2581a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                    } catch (IOException e) {
2582a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                        // Ignore
2583a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                    }
2584a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                }
2585a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            }
2586a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        }
2587a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    }
2588a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie
2589a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    private static void log(String msg) {
2590a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        Log.d(TAG, msg);
2591a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    }
2592a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie
2593d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native static void classInitNative();
2594d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native void initializeNativeDataNative();
2595d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setupNativeDataNative();
2596d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean tearDownNativeDataNative();
2597d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native void cleanupNativeDataNative();
25989a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    /*package*/ native String getAdapterPathNative();
2599d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
2600d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native int isEnabledNative();
2601d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native int enableNative();
2602d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native int disableNative();
2603d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
26049a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    /*package*/ native Object[] getAdapterPropertiesNative();
2605d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native Object[] getDevicePropertiesNative(String objectPath);
2606d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setAdapterPropertyStringNative(String key, String value);
2607d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setAdapterPropertyIntegerNative(String key, int value);
2608d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setAdapterPropertyBooleanNative(String key, int value);
2609d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
2610d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean startDiscoveryNative();
2611d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean stopDiscoveryNative();
2612d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
2613d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean createPairedDeviceNative(String address, int timeout_ms);
2614cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    private native boolean createPairedDeviceOutOfBandNative(String address, int timeout_ms);
2615cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    private native byte[] readAdapterOutOfBandDataNative();
2616cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
2617d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean cancelDeviceCreationNative(String address);
2618d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean removeDeviceNative(String objectPath);
2619d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native int getDeviceServiceChannelNative(String objectPath, String uuid,
2620d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            int attributeId);
2621d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
2622b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    private native boolean cancelPairingUserInputNative(String address, int nativeData);
2623d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setPinNative(String address, String pin, int nativeData);
2624b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    private native boolean setPasskeyNative(String address, int passkey, int nativeData);
2625b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    private native boolean setPairingConfirmationNative(String address, boolean confirm,
2626b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            int nativeData);
2627cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    private native boolean setRemoteOutOfBandDataNative(String address, byte[] hash,
2628cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh                                                        byte[] randomizer, int nativeData);
2629cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
263024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private native boolean setDevicePropertyBooleanNative(String objectPath, String key,
263124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            int value);
26321caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    private native boolean createDeviceNative(String address);
263316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    /*package*/ native boolean discoverServicesNative(String objectPath, String pattern);
263410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
263524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private native int addRfcommServiceRecordNative(String name, long uuidMsb, long uuidLsb,
263624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            short channel);
263724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private native boolean removeServiceRecordNative(int handle);
2638b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh    private native boolean setLinkTimeoutNative(String path, int num_slots);
2639a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie
264030b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    native boolean connectInputDeviceNative(String path);
264130b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    native boolean disconnectInputDeviceNative(String path);
26426fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang
2643a8571f15c39da2b7c6e672fef26106f5ac60dea0Jaikumar Ganesh    native boolean setBluetoothTetheringNative(boolean value, String nap, String bridge);
2644a8571f15c39da2b7c6e672fef26106f5ac60dea0Jaikumar Ganesh    native boolean connectPanDeviceNative(String path, String dstRole);
2645a8571f15c39da2b7c6e672fef26106f5ac60dea0Jaikumar Ganesh    native boolean disconnectPanDeviceNative(String path);
2646a8571f15c39da2b7c6e672fef26106f5ac60dea0Jaikumar Ganesh    native boolean disconnectPanServerDeviceNative(String path,
2647a44a1e77ef435942b2ff60e9e60d3a64b43d775bJaikumar Ganesh            String address, String iface);
264884690c88f37f395094147d27ace8319a2803a522Jaikumar Ganesh
264984690c88f37f395094147d27ace8319a2803a522Jaikumar Ganesh    private native int[] addReservedServiceRecordsNative(int[] uuuids);
265084690c88f37f395094147d27ace8319a2803a522Jaikumar Ganesh    private native boolean removeReservedServiceRecordsNative(int[] handles);
26512ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
26522ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    // Health API
26532ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    native String registerHealthApplicationNative(int dataType, String role, String name,
26542ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            String channelType);
26552ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    native String registerHealthApplicationNative(int dataType, String role, String name);
26562ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    native boolean unregisterHealthApplicationNative(String path);
26572ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    native boolean createChannelNative(String devicePath, String appPath, String channelType);
26582ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    native boolean destroyChannelNative(String devicePath, String channelpath);
26592ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    native String getMainChannelNative(String path);
26602ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    native String getChannelApplicationNative(String channelPath);
26612ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    native ParcelFileDescriptor getChannelFdNative(String channelPath);
26622ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    native boolean releaseChannelFdNative(String channelPath);
2663a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    native boolean setAuthorizationNative(String address, boolean value, int data);
26649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
2665