BluetoothService.java revision 7d0548d0944e48421857de4aec2822ced325bea0
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;
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.bluetooth.BluetoothHeadset;
31f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganeshimport android.bluetooth.BluetoothDeviceProfileState;
326fdd0c6274c81b337ad35b70480f881daf7354c3Danica Changimport android.bluetooth.BluetoothPan;
3396a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganeshimport android.bluetooth.BluetoothProfile;
34f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganeshimport android.bluetooth.BluetoothProfileState;
35545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganeshimport android.bluetooth.BluetoothInputDevice;
3624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pellyimport android.bluetooth.BluetoothSocket;
3710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganeshimport android.bluetooth.BluetoothUuid;
38bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pellyimport android.bluetooth.IBluetooth;
3916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pellyimport android.bluetooth.IBluetoothCallback;
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.BroadcastReceiver;
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ContentResolver;
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Intent;
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.IntentFilter;
456e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganeshimport android.content.SharedPreferences;
46707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganeshimport android.content.res.Resources.NotFoundException;
476fdd0c6274c81b337ad35b70480f881daf7354c3Danica Changimport android.net.ConnectivityManager;
486fdd0c6274c81b337ad35b70480f881daf7354c3Danica Changimport android.net.InterfaceConfiguration;
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Binder;
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Handler;
513fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport android.os.IBinder;
526fdd0c6274c81b337ad35b70480f881daf7354c3Danica Changimport android.os.INetworkManagementService;
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Message;
543fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport android.os.ParcelUuid;
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.RemoteException;
56105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Projectimport android.os.ServiceManager;
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemService;
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.Settings;
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log;
60cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganeshimport android.util.Pair;
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
62d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganeshimport com.android.internal.app.IBatteryStats;
63d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
643fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.BufferedInputStream;
65c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganeshimport java.io.BufferedReader;
663fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.BufferedWriter;
67c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganeshimport java.io.DataInputStream;
68c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganeshimport java.io.File;
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileDescriptor;
703fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.FileInputStream;
713fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.FileNotFoundException;
72c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganeshimport java.io.FileOutputStream;
733fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.FileWriter;
743fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.IOException;
75c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganeshimport java.io.InputStreamReader;
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.PrintWriter;
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.UnsupportedEncodingException;
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList;
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Arrays;
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.HashMap;
81545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganeshimport java.util.HashSet;
8216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pellyimport java.util.Iterator;
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Map;
84545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganeshimport java.util.Set;
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
86bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pellypublic class BluetoothService extends IBluetooth.Stub {
87bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    private static final String TAG = "BluetoothService";
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final boolean DBG = true;
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mNativeData;
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private BluetoothEventLoop mEventLoop;
9296a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh    private BluetoothHeadset mBluetoothHeadset;
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mIsAirplaneSensitive;
9444303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey    private boolean mIsAirplaneToggleable;
95105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private int mBluetoothState;
96997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly    private boolean mRestart = false;  // need to call enable() after disable()
97bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    private boolean mIsDiscovering;
986fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang    private boolean mTetheringOn;
99997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly
100bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    private BluetoothAdapter mAdapter;  // constant after init()
101997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly    private final BondState mBondState = new BondState();  // 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;
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private 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
114105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private static final int MESSAGE_REGISTER_SDP_RECORDS = 1;
115105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private static final int MESSAGE_FINISH_DISABLE = 2;
1161caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    private static final int MESSAGE_UUID_INTENT = 3;
11712835478ee687a493d1b5882e67b6725bd539c26Nick Pelly    private static final int MESSAGE_DISCOVERABLE_TIMEOUT = 4;
118a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    private static final int MESSAGE_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 5;
119a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh
120a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    // The time (in millisecs) to delay the pairing attempt after the first
121a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    // auto pairing attempt fails. We use an exponential delay with
122a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    // INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY as the initial value and
123a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    // MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY as the max value.
124a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    private static final long INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 3000;
125a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    private static final long MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 12000;
1261caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
1276fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang    private ArrayList<String> mBluetoothIfaceAddresses;
128707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh    private int mMaxPanDevices;
129707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh
130707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh    private static final String BLUETOOTH_IFACE_ADDR_START= "192.168.44.1";
131707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh    private static final int BLUETOOTH_MAX_PAN_CONNECTIONS = 5;
1326fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang    private static final String BLUETOOTH_NETMASK        = "255.255.255.0";
1336fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang
1341caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    // The timeout used to sent the UUIDs Intent
1351caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    // This timeout should be greater than the page timeout
1361caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    private static final int UUID_INTENT_DELAY = 6000;
137105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
13816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    /** Always retrieve RFCOMM channel for these SDP UUIDs */
13916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private static final ParcelUuid[] RFCOMM_UUIDS = {
14016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            BluetoothUuid.Handsfree,
14116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            BluetoothUuid.HSP,
14216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            BluetoothUuid.ObexObjectPush };
14316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
1449b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    // TODO(): Optimize all these string handling
145bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    private final Map<String, String> mAdapterProperties;
14616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private final HashMap<String, Map<String, String>> mDeviceProperties;
147d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
14816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private final HashMap<String, Map<ParcelUuid, Integer>> mDeviceServiceChannelCache;
14916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private final ArrayList<String> mUuidIntentTracker;
15016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private final HashMap<RemoteService, IBluetoothCallback> mUuidCallbackTracker;
1511caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
15224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private final HashMap<Integer, Integer> mServiceRecordToPid;
15324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
154f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh    private final HashMap<String, BluetoothDeviceProfileState> mDeviceProfileState;
155f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh    private final BluetoothProfileState mA2dpProfileState;
156f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh    private final BluetoothProfileState mHfpProfileState;
157de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh    private final BluetoothProfileState mHidProfileState;
1589b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
1599b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    private BluetoothA2dpService mA2dpService;
160545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh    private final HashMap<BluetoothDevice, Integer> mInputDevices;
161707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh    private final HashMap<BluetoothDevice, Pair<Integer, String>> mPanDevices;
162cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    private final HashMap<String, Pair<byte[], byte[]>> mDeviceOobData;
163545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh
164707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh
1653fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    private static String mDockAddress;
1663fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    private String mDockPin;
1673fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
16816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private static class RemoteService {
16916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        public String address;
17016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        public ParcelUuid uuid;
17116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        public RemoteService(String address, ParcelUuid uuid) {
17216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            this.address = address;
17316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            this.uuid = uuid;
17416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
17516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        @Override
17616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        public boolean equals(Object o) {
17716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (o instanceof RemoteService) {
17816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                RemoteService service = (RemoteService)o;
17916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                return address.equals(service.address) && uuid.equals(service.uuid);
18016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
18116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            return false;
18216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
1835f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root
1845f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root        @Override
1855f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root        public int hashCode() {
1865f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root            int hash = 1;
1875f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root            hash = hash * 31 + (address == null ? 0 : address.hashCode());
1885f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root            hash = hash * 31 + (uuid == null ? 0 : uuid.hashCode());
1895f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root            return hash;
1905f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root        }
19116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    }
19216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static {
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        classInitNative();
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
197bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    public BluetoothService(Context context) {
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext = context;
199105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
200105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Need to do this in place of:
201105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // mBatteryStats = BatteryStatsService.getService();
202105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Since we can not import BatteryStatsService from here. This class really needs to be
203105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // moved to java/services/com/android/server/
204105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo"));
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        initializeNativeDataNative();
207ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project
208ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project        if (isEnabledNative() == 1) {
209ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project            Log.w(TAG, "Bluetooth daemons already running - runtime restart? ");
210ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project            disableNative();
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
212ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project
213de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        mBluetoothState = BluetoothAdapter.STATE_OFF;
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mIsDiscovering = false;
2156fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        mTetheringOn = false;
216bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mAdapterProperties = new HashMap<String, String>();
217bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mDeviceProperties = new HashMap<String, Map<String,String>>();
21810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
21910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        mDeviceServiceChannelCache = new HashMap<String, Map<ParcelUuid, Integer>>();
220cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        mDeviceOobData = new HashMap<String, Pair<byte[], byte[]>>();
2211caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        mUuidIntentTracker = new ArrayList<String>();
22216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        mUuidCallbackTracker = new HashMap<RemoteService, IBluetoothCallback>();
22324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        mServiceRecordToPid = new HashMap<Integer, Integer>();
224f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        mDeviceProfileState = new HashMap<String, BluetoothDeviceProfileState>();
225f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        mA2dpProfileState = new BluetoothProfileState(mContext, BluetoothProfileState.A2DP);
226f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        mHfpProfileState = new BluetoothProfileState(mContext, BluetoothProfileState.HFP);
227de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh        mHidProfileState = new BluetoothProfileState(mContext, BluetoothProfileState.HID);
228f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh
229707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh        mBluetoothIfaceAddresses = new ArrayList<String>();
230707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh        try {
231707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh            mMaxPanDevices = context.getResources().getInteger(
232707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh                            com.android.internal.R.integer.config_max_pan_devices);
233707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh        } catch (NotFoundException e) {
234707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh            mMaxPanDevices = BLUETOOTH_MAX_PAN_CONNECTIONS;
2356fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        }
2366fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang
237f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        mHfpProfileState.start();
238f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        mA2dpProfileState.start();
239de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh        mHidProfileState.start();
2403fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
2413fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        IntentFilter filter = new IntentFilter();
2426e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh        registerForAirplaneMode(filter);
2436e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh
2443fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        filter.addAction(Intent.ACTION_DOCK_EVENT);
2456e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh        mContext.registerReceiver(mReceiver, filter);
246545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        mInputDevices = new HashMap<BluetoothDevice, Integer>();
247707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh        mPanDevices = new HashMap<BluetoothDevice, Pair<Integer, String>>();
2483fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    }
2493fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
2509b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public static synchronized String readDockBluetoothAddress() {
2513fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        if (mDockAddress != null) return mDockAddress;
2523fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
2533fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        BufferedInputStream file = null;
2543fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        String dockAddress;
2553fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        try {
2563fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            file = new BufferedInputStream(new FileInputStream(DOCK_ADDRESS_PATH));
2573fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            byte[] address = new byte[17];
2583fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            file.read(address);
2593fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            dockAddress = new String(address);
2603fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            dockAddress = dockAddress.toUpperCase();
2613fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            if (BluetoothAdapter.checkBluetoothAddress(dockAddress)) {
2623fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                mDockAddress = dockAddress;
2633fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                return mDockAddress;
2643fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            } else {
2653fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                log("CheckBluetoothAddress failed for car dock address:" + dockAddress);
2663fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            }
2673fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        } catch (FileNotFoundException e) {
2683fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            log("FileNotFoundException while trying to read dock address");
2693fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        } catch (IOException e) {
2703fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            log("IOException while trying to read dock address");
2713fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        } finally {
2723fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            if (file != null) {
2733fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                try {
2743fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                    file.close();
2753fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                } catch (IOException e) {
2763fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                    // Ignore
2773fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                }
2783fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            }
2793fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        }
2803fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        mDockAddress = null;
2813fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        return null;
2823fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    }
2833fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
2843fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    private synchronized boolean writeDockPin() {
2853fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        BufferedWriter out = null;
2863fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        try {
2873fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            out = new BufferedWriter(new FileWriter(DOCK_PIN_PATH));
2883fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
2893fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            // Generate a random 4 digit pin between 0000 and 9999
2903fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            // This is not truly random but good enough for our purposes.
2913fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            int pin = (int) Math.floor(Math.random() * 10000);
2923fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
2933fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            mDockPin = String.format("%04d", pin);
2943fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            out.write(mDockPin);
2953fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            return true;
2963fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        } catch (FileNotFoundException e) {
2973fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            log("FileNotFoundException while trying to write dock pairing pin");
2983fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        } catch (IOException e) {
2993fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            log("IOException while while trying to write dock pairing pin");
3003fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        } finally {
3013fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            if (out != null) {
3023fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                try {
3033fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                    out.close();
3043fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                } catch (IOException e) {
3053fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                    // Ignore
3063fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                }
3073fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            }
3083fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        }
3093fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        mDockPin = null;
3103fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        return false;
3113fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    }
3123fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
3133fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    /*package*/ synchronized String getDockPin() {
3143fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        return mDockPin;
315bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    }
316bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly
317bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    public synchronized void initAfterRegistration() {
318f242b7b931898856bcbcb7ec36cacf43098ba544Nick Pelly        mAdapter = BluetoothAdapter.getDefaultAdapter();
319bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mEventLoop = new BluetoothEventLoop(mContext, mAdapter, this);
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3227d0548d0944e48421857de4aec2822ced325bea0Jaikumar Ganesh    public synchronized void initAfterA2dpRegistration() {
3237d0548d0944e48421857de4aec2822ced325bea0Jaikumar Ganesh        mEventLoop.getProfileProxy();
3247d0548d0944e48421857de4aec2822ced325bea0Jaikumar Ganesh    }
3257d0548d0944e48421857de4aec2822ced325bea0Jaikumar Ganesh
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void finalize() throws Throwable {
3286e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh        mContext.unregisterReceiver(mReceiver);
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            cleanupNativeDataNative();
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super.finalize();
3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean isEnabled() {
3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
3388c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        return isEnabledInternal();
3398c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh    }
3408c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
3418c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh    private boolean isEnabledInternal() {
342de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        return mBluetoothState == BluetoothAdapter.STATE_ON;
3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
345105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    public int getBluetoothState() {
346105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
347105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        return mBluetoothState;
348105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    }
349105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
350105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Bring down bluetooth and disable BT in settings. Returns true on success.
3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean disable() {
3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return disable(true);
3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Bring down bluetooth. Returns true on success.
3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
361e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly     * @param saveSetting If true, persist the new setting
3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean disable(boolean saveSetting) {
364e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission");
3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
366105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        switch (mBluetoothState) {
367de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_OFF:
368105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return true;
369de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_ON:
370105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            break;
371105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        default:
372105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return false;
373105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mEnableThread != null && mEnableThread.isAlive()) {
3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
377de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        setBluetoothState(BluetoothAdapter.STATE_TURNING_OFF);
378bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly        mHandler.removeMessages(MESSAGE_REGISTER_SDP_RECORDS);
379b70765cc27a174d1d4a0bab7062733ebd3eae354Jaikumar Ganesh        setBluetoothTetheringNative(false, BluetoothPan.NAP_ROLE, BluetoothPan.NAP_BRIDGE);
380105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
381105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Allow 3 seconds for profiles to gracefully disconnect
382105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // TODO: Introduce a callback mechanism so that each profile can notify
383bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        // BluetoothService when it is done shutting down
384105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mHandler.sendMessageDelayed(
385105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                mHandler.obtainMessage(MESSAGE_FINISH_DISABLE, saveSetting ? 1 : 0, 0), 3000);
386105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        return true;
387105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    }
388105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
389105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
390105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private synchronized void finishDisable(boolean saveSetting) {
391de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        if (mBluetoothState != BluetoothAdapter.STATE_TURNING_OFF) {
392105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return;
3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mEventLoop.stop();
395d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        tearDownNativeDataNative();
3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        disableNative();
3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // mark in progress bondings as cancelled
3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (String address : mBondState.listInState(BluetoothDevice.BOND_BONDING)) {
400005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            mBondState.setBondState(address, BluetoothDevice.BOND_NONE,
4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // update mode
405de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        Intent intent = new Intent(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
406de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        intent.putExtra(BluetoothAdapter.EXTRA_SCAN_MODE, BluetoothAdapter.SCAN_MODE_NONE);
4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.sendBroadcast(intent, BLUETOOTH_PERM);
4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
409105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mIsDiscovering = false;
410bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mAdapterProperties.clear();
41124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        mServiceRecordToPid.clear();
412105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (saveSetting) {
4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            persistBluetoothOnSetting(false);
4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
416105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
417de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        setBluetoothState(BluetoothAdapter.STATE_OFF);
418105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
419105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Log bluetooth off to battery stats.
420105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        long ident = Binder.clearCallingIdentity();
421105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        try {
422105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            mBatteryStats.noteBluetoothOff();
423105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        } catch (RemoteException e) {
424105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        } finally {
425105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            Binder.restoreCallingIdentity(ident);
426105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
427997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly
428997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        if (mRestart) {
429997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly            mRestart = false;
430997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly            enable();
431997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        }
4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
434105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    /** Bring up BT and persist BT on in settings */
435105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    public boolean enable() {
436105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        return enable(true);
4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Enable this Bluetooth device, asynchronously.
4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * This turns on/off the underlying hardware.
4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
443105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project     * @param saveSetting If true, persist the new state of BT in settings
444105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project     * @return True on success (so far)
4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
446105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    public synchronized boolean enable(boolean saveSetting) {
4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Airplane mode can prevent Bluetooth radio from being turned on.
45144303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        if (mIsAirplaneSensitive && isAirplaneModeOn() && !mIsAirplaneToggleable) {
4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
454de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        if (mBluetoothState != BluetoothAdapter.STATE_OFF) {
4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mEnableThread != null && mEnableThread.isAlive()) {
4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
460de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        setBluetoothState(BluetoothAdapter.STATE_TURNING_ON);
461105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mEnableThread = new EnableThread(saveSetting);
4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mEnableThread.start();
4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
466997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly    /** Forcibly restart Bluetooth if it is on */
467997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly    /* package */ synchronized void restart() {
468de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        if (mBluetoothState != BluetoothAdapter.STATE_ON) {
469997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly            return;
470997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        }
471997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        mRestart = true;
472997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        if (!disable(false)) {
473997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly            mRestart = false;
474997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        }
475d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
476997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly
477105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private synchronized void setBluetoothState(int state) {
478105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        if (state == mBluetoothState) {
479105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return;
480105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
481105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
482105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        if (DBG) log("Bluetooth state " + mBluetoothState + " -> " + state);
483105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
484de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
485de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, mBluetoothState);
486de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        intent.putExtra(BluetoothAdapter.EXTRA_STATE, state);
487105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
488105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
489105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mBluetoothState = state;
490105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
491105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mContext.sendBroadcast(intent, BLUETOOTH_PERM);
492105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    }
493105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final Handler mHandler = new Handler() {
4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void handleMessage(Message msg) {
4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            switch (msg.what) {
498105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            case MESSAGE_REGISTER_SDP_RECORDS:
4998c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh                if (!isEnabledInternal()) {
500bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    return;
501bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                }
502bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                // SystemService.start() forks sdptool to register service
503bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                // records. It can fail to register some records if it is
504bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                // forked multiple times in a row, probably because there is
505bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                // some race in sdptool or bluez when operated in parallel.
506bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                // As a workaround, delay 500ms between each fork of sdptool.
507f51eadaf1f83abfe16a609a4ded6d789494689b2Jake Hamby                // TODO: Don't fork sdptool in order to register service
508bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                // records, use a DBUS call instead.
509bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                switch (msg.arg1) {
510bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                case 1:
51177b4ad0e496941a28382eb938a05831f1f8d2d4aJaikumar Ganesh                    Log.d(TAG, "Registering hfag record");
51277b4ad0e496941a28382eb938a05831f1f8d2d4aJaikumar Ganesh                    SystemService.start("hfag");
513bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    mHandler.sendMessageDelayed(
514bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                            mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS, 2, -1), 500);
515bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    break;
516bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                case 2:
51777b4ad0e496941a28382eb938a05831f1f8d2d4aJaikumar Ganesh                    Log.d(TAG, "Registering hsag record");
51877b4ad0e496941a28382eb938a05831f1f8d2d4aJaikumar Ganesh                    SystemService.start("hsag");
519bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    mHandler.sendMessageDelayed(
520bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                            mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS, 3, -1), 500);
521bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    break;
522bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                case 3:
523bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    Log.d(TAG, "Registering opush record");
52403c707ab6fc97e99b1603b8d6edc604dbea3cd6fNick Pelly                    SystemService.start("opush");
525bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    mHandler.sendMessageDelayed(
526bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                            mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS, 4, -1), 500);
527bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    break;
528bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                case 4:
529bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    Log.d(TAG, "Registering pbap record");
53067542964876aa7e4216e8f69f21dda68e7463b9aJaikumar Ganesh                    SystemService.start("pbap");
531bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    break;
5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
533105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                break;
534105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            case MESSAGE_FINISH_DISABLE:
535105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                finishDisable(msg.arg1 != 0);
536105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                break;
5371caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            case MESSAGE_UUID_INTENT:
5381caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh                String address = (String)msg.obj;
53916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (address != null) {
5401caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh                    sendUuidIntent(address);
54116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    makeServiceChannelCallbacks(address);
54216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                }
5431caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh                break;
54412835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            case MESSAGE_DISCOVERABLE_TIMEOUT:
54512835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                int mode = msg.arg1;
5468c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh                if (isEnabledInternal()) {
54712835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                    // TODO: Switch back to the previous scan mode
54812835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                    // This is ok for now, because we only use
54912835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                    // CONNECTABLE and CONNECTABLE_DISCOVERABLE
55012835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                    setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE, -1);
55112835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                }
55212835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                break;
553a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            case MESSAGE_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY:
554a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                address = (String)msg.obj;
555a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                if (address != null) {
556a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                    createBond(address);
557a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                    return;
558a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                }
559a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                break;
5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private EnableThread mEnableThread;
5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private class EnableThread extends Thread {
5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final boolean mSaveSetting;
568105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        public EnableThread(boolean saveSetting) {
5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mSaveSetting = saveSetting;
5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void run() {
5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean res = (enableNative() == 0);
5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (res) {
574b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                int retryCount = 2;
575b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                boolean running = false;
576b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                while ((retryCount-- > 0) && !running) {
577b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    mEventLoop.start();
578105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    // it may take a momement for the other thread to do its
579b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    // thing.  Check periodically for a while.
580b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    int pollCount = 5;
581b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    while ((pollCount-- > 0) && !running) {
582b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                        if (mEventLoop.isEventLoopRunning()) {
583b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                            running = true;
584b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                            break;
585b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                        }
586b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                        try {
587b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                            Thread.sleep(100);
588b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                        } catch (InterruptedException e) {}
589b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    }
590b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                }
591b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                if (!running) {
592b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    log("bt EnableThread giving up");
593b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    res = false;
594b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    disableNative();
595b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                }
5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (res) {
600d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                if (!setupNativeDataNative()) {
601d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                    return;
602d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                }
6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mSaveSetting) {
6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    persistBluetoothOnSetting(true);
6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mIsDiscovering = false;
607c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                mBondState.readAutoPairingData();
6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mBondState.loadBondState();
6099b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                initProfileState();
610b70765cc27a174d1d4a0bab7062733ebd3eae354Jaikumar Ganesh
611b70765cc27a174d1d4a0bab7062733ebd3eae354Jaikumar Ganesh                //Register SDP records.
612bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                mHandler.sendMessageDelayed(
613bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                        mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS, 1, -1), 3000);
614b70765cc27a174d1d4a0bab7062733ebd3eae354Jaikumar Ganesh                setBluetoothTetheringNative(true, BluetoothPan.NAP_ROLE, BluetoothPan.NAP_BRIDGE);
615b70765cc27a174d1d4a0bab7062733ebd3eae354Jaikumar Ganesh
6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
617105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                // Log bluetooth on to battery stats.
618105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                long ident = Binder.clearCallingIdentity();
619105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                try {
620105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    mBatteryStats.noteBluetoothOn();
621105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                } catch (RemoteException e) {
622105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                } finally {
623105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    Binder.restoreCallingIdentity(ident);
624105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                }
6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
626105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
627105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            mEnableThread = null;
628105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
629105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            setBluetoothState(res ?
630de893f550301a60274e87aa8168225e7a7a42184Nick Pelly                              BluetoothAdapter.STATE_ON :
631de893f550301a60274e87aa8168225e7a7a42184Nick Pelly                              BluetoothAdapter.STATE_OFF);
632105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
633b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            if (res) {
634105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                // Update mode
635d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                String[] propVal = {"Pairable", getProperty("Pairable")};
636d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                mEventLoop.onPropertyChanged(propVal);
637b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            }
638b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project
63944303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey            if (mIsAirplaneSensitive && isAirplaneModeOn() && !mIsAirplaneToggleable) {
6405c43f735d94a538dc273c8f859d1100a7cdd5c71Daisuke Miyakawa                disable(false);
6415c43f735d94a538dc273c8f859d1100a7cdd5c71Daisuke Miyakawa            }
6425c43f735d94a538dc273c8f859d1100a7cdd5c71Daisuke Miyakawa
6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void persistBluetoothOnSetting(boolean bluetoothOn) {
6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long origCallerIdentityToken = Binder.clearCallingIdentity();
6489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.BLUETOOTH_ON,
6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                bluetoothOn ? 1 : 0);
6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Binder.restoreCallingIdentity(origCallerIdentityToken);
6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
653a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    /*package*/ synchronized boolean attemptAutoPair(String address) {
654a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        if (!mBondState.hasAutoPairingFailed(address) &&
655a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                !mBondState.isAutoPairingBlacklisted(address)) {
656a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            mBondState.attempt(address);
657a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            setPin(address, BluetoothDevice.convertPinToBytes("0000"));
658a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            return true;
659a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        }
660a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        return false;
661a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    }
662a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh
663a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    /*package*/ synchronized void onCreatePairedDeviceResult(String address, int result) {
664a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        if (result == BluetoothDevice.BOND_SUCCESS) {
665a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            setBondState(address, BluetoothDevice.BOND_BONDED);
666a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            if (mBondState.isAutoPairingAttemptsInProgress(address)) {
667a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                mBondState.clearPinAttempts(address);
668a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            }
669a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        } else if (result == BluetoothDevice.UNBOND_REASON_AUTH_FAILED &&
670a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                mBondState.getAttempt(address) == 1) {
671a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            mBondState.addAutoPairingFailure(address);
672a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            pairingAttempt(address, result);
673a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        } else if (result == BluetoothDevice.UNBOND_REASON_REMOTE_DEVICE_DOWN &&
674a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh              mBondState.isAutoPairingAttemptsInProgress(address)) {
675a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            pairingAttempt(address, result);
676a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        } else {
677a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            setBondState(address, BluetoothDevice.BOND_NONE, result);
678a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            if (mBondState.isAutoPairingAttemptsInProgress(address)) {
679a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                mBondState.clearPinAttempts(address);
680a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            }
681a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        }
682a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    }
683a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh
684a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    /*package*/ synchronized String getPendingOutgoingBonding() {
685a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        return mBondState.getPendingOutgoingBonding();
686a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    }
687a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh
688a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    private void pairingAttempt(String address, int result) {
689a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        // This happens when our initial guess of "0000" as the pass key
690a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        // fails. Try to create the bond again and display the pin dialog
691a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        // to the user. Use back-off while posting the delayed
692a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        // message. The initial value is
693a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        // INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY and the max value is
694a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        // MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY. If the max value is
695a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        // reached, display an error to the user.
696a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        int attempt = mBondState.getAttempt(address);
697a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        if (attempt * INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY >
698a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                    MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY) {
699a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            mBondState.clearPinAttempts(address);
700a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            setBondState(address, BluetoothDevice.BOND_NONE, result);
701a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            return;
702a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        }
703a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh
704a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        Message message = mHandler.obtainMessage(MESSAGE_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY);
705a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        message.obj = address;
706a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        boolean postResult =  mHandler.sendMessageDelayed(message,
707a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                                        attempt * INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY);
708a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        if (!postResult) {
709a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            mBondState.clearPinAttempts(address);
710a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            setBondState(address,
711a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                    BluetoothDevice.BOND_NONE, result);
712a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            return;
713a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        }
714a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        mBondState.attempt(address);
7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** local cache of bonding state.
7189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* we keep our own state to track the intermediate state BONDING, which
7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* bluez does not track.
720f51eadaf1f83abfe16a609a4ded6d789494689b2Jake Hamby     * All addresses must be passed in upper case.
7219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
7229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public class BondState {
7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final HashMap<String, Integer> mState = new HashMap<String, Integer>();
7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final HashMap<String, Integer> mPinAttempt = new HashMap<String, Integer>();
725c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh
726c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        private static final String AUTO_PAIRING_BLACKLIST =
727c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            "/etc/bluetooth/auto_pairing.conf";
728c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        private static final String DYNAMIC_AUTO_PAIRING_BLACKLIST =
729c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            "/data/misc/bluetooth/dynamic_auto_pairing.conf";
730c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        private ArrayList<String>  mAutoPairingAddressBlacklist;
731c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        private ArrayList<String> mAutoPairingExactNameBlacklist;
732c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        private ArrayList<String> mAutoPairingPartialNameBlacklist;
733c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        // Addresses added to blacklist dynamically based on usage.
734c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        private ArrayList<String> mAutoPairingDynamicAddressBlacklist;
735c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh
736482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh
7372092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        // If this is an outgoing connection, store the address.
7382092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        // There can be only 1 pending outgoing connection at a time,
7392092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        private String mPendingOutgoingBonding;
7402092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
7412092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        private synchronized void setPendingOutgoingBonding(String address) {
7422092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh            mPendingOutgoingBonding = address;
7432092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        }
7442092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
7452092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        public synchronized String getPendingOutgoingBonding() {
7462092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh            return mPendingOutgoingBonding;
7472092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        }
7482092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
7499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized void loadBondState() {
750de893f550301a60274e87aa8168225e7a7a42184Nick Pelly            if (mBluetoothState != BluetoothAdapter.STATE_TURNING_ON) {
7519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
7529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
753d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            String []bonds = null;
754b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh            String val = getPropertyInternal("Devices");
755d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            if (val != null) {
756d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                bonds = val.split(",");
757d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            }
7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (bonds == null) {
7599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mState.clear();
7629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (DBG) log("found " + bonds.length + " bonded devices");
763d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            for (String device : bonds) {
764d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                mState.put(getAddressFromObjectPath(device).toUpperCase(),
765d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                        BluetoothDevice.BOND_BONDED);
7669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized void setBondState(String address, int state) {
7709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setBondState(address, state, 0);
7719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /** reason is ignored unless state == BOND_NOT_BONDED */
7749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized void setBondState(String address, int state, int reason) {
7759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int oldState = getBondState(address);
7769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (oldState == state) {
7779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
7789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7792092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
7802092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh            // Check if this was an pending outgoing bonding.
7812092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh            // If yes, reset the state.
7822092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh            if (oldState == BluetoothDevice.BOND_BONDING) {
7832092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh                if (address.equals(mPendingOutgoingBonding)) {
7842092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh                    mPendingOutgoingBonding = null;
7852092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh                }
7862092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh            }
7872092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
7889b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            if (state == BluetoothDevice.BOND_BONDED) {
7899b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                addProfileState(address);
7909b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            } else if (state == BluetoothDevice.BOND_NONE) {
7919b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                removeProfileState(address);
7929b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            }
7939b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
794c3ee99d9eb7e8b4b20c2b8f1c548373e1017e0d3Jaikumar Ganesh            // HID is handled by BluetoothService, other profiles
795c3ee99d9eb7e8b4b20c2b8f1c548373e1017e0d3Jaikumar Ganesh            // will be handled by their respective services.
796c3ee99d9eb7e8b4b20c2b8f1c548373e1017e0d3Jaikumar Ganesh            setInitialInputDevicePriority(mAdapter.getRemoteDevice(address), state);
797c3ee99d9eb7e8b4b20c2b8f1c548373e1017e0d3Jaikumar Ganesh
7989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (DBG) log(address + " bond state " + oldState + " -> " + state + " (" +
7999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                         reason + ")");
800005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            Intent intent = new Intent(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
801005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
802005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            intent.putExtra(BluetoothDevice.EXTRA_BOND_STATE, state);
803005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            intent.putExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, oldState);
804005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            if (state == BluetoothDevice.BOND_NONE) {
8059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (reason <= 0) {
8069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Log.w(TAG, "setBondState() called to unbond device, but reason code is " +
8079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                          "invalid. Overriding reason code with BOND_RESULT_REMOVED");
8089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    reason = BluetoothDevice.UNBOND_REASON_REMOVED;
8099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
810005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly                intent.putExtra(BluetoothDevice.EXTRA_REASON, reason);
8119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mState.remove(address);
8129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
8139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mState.put(address, state);
8149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mContext.sendBroadcast(intent, BLUETOOTH_PERM);
8179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public boolean isAutoPairingBlacklisted(String address) {
820c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            if (mAutoPairingAddressBlacklist != null) {
821c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                for (String blacklistAddress : mAutoPairingAddressBlacklist) {
822c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    if (address.startsWith(blacklistAddress)) return true;
823c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                }
8249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
825482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh
826c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            if (mAutoPairingDynamicAddressBlacklist != null) {
827c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                for (String blacklistAddress: mAutoPairingDynamicAddressBlacklist) {
828c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    if (address.equals(blacklistAddress)) return true;
829c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                }
830c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            }
831482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh            String name = getRemoteName(address);
832482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh            if (name != null) {
833c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                if (mAutoPairingExactNameBlacklist != null) {
834c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    for (String blacklistName : mAutoPairingExactNameBlacklist) {
835c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        if (name.equals(blacklistName)) return true;
836c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    }
837738ed80262aa26128924c51f59ffd49e1163eb8dJaikumar Ganesh                }
838738ed80262aa26128924c51f59ffd49e1163eb8dJaikumar Ganesh
839c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                if (mAutoPairingPartialNameBlacklist != null) {
840c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    for (String blacklistName : mAutoPairingPartialNameBlacklist) {
841c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        if (name.startsWith(blacklistName)) return true;
842c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    }
843482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh                }
844482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh            }
8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
8469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized int getBondState(String address) {
8499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Integer state = mState.get(address);
8509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (state == null) {
851005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly                return BluetoothDevice.BOND_NONE;
8529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return state.intValue();
8549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
856e5d93b7ed983f98855555d560faf060836f1a52fJaikumar Ganesh        /*package*/ synchronized String[] listInState(int state) {
8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ArrayList<String> result = new ArrayList<String>(mState.size());
8589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (Map.Entry<String, Integer> e : mState.entrySet()) {
8599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (e.getValue().intValue() == state) {
8609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    result.add(e.getKey());
8619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
8629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return result.toArray(new String[result.size()]);
8649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized void addAutoPairingFailure(String address) {
867c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            if (mAutoPairingDynamicAddressBlacklist == null) {
868c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                mAutoPairingDynamicAddressBlacklist = new ArrayList<String>();
8699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
870c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh
871c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            updateAutoPairingData(address);
872c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            mAutoPairingDynamicAddressBlacklist.add(address);
8739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized boolean isAutoPairingAttemptsInProgress(String address) {
8769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return getAttempt(address) != 0;
8779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized void clearPinAttempts(String address) {
8809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mPinAttempt.remove(address);
8819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized boolean hasAutoPairingFailed(String address) {
884c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            if (mAutoPairingDynamicAddressBlacklist == null) return false;
885c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh
886c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            return mAutoPairingDynamicAddressBlacklist.contains(address);
8879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized int getAttempt(String address) {
8909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Integer attempt = mPinAttempt.get(address);
8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (attempt == null) {
8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return 0;
8939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return attempt.intValue();
8959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized void attempt(String address) {
8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Integer attempt = mPinAttempt.get(address);
8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int newAttempt;
9009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (attempt == null) {
9019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                newAttempt = 1;
9029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
9039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                newAttempt = attempt.intValue() + 1;
9049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mPinAttempt.put(address, new Integer(newAttempt));
9069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
908c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        private void copyAutoPairingData() {
909c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            File file = null;
910c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            FileInputStream in = null;
911c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            FileOutputStream out = null;
912c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            try {
913c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                file = new File(DYNAMIC_AUTO_PAIRING_BLACKLIST);
914c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                if (file.exists()) return;
915c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh
916c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                in = new FileInputStream(AUTO_PAIRING_BLACKLIST);
917c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                out= new FileOutputStream(DYNAMIC_AUTO_PAIRING_BLACKLIST);
918c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh
919c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                byte[] buf = new byte[1024];
920c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                int len;
921c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                while ((len = in.read(buf)) > 0) {
922c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    out.write(buf, 0, len);
923c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                }
924c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            } catch (FileNotFoundException e) {
925c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                log("FileNotFoundException: in copyAutoPairingData");
926c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            } catch (IOException e) {
927c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                log("IOException: in copyAutoPairingData");
928c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            } finally {
929c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                 try {
930c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                     if (in != null) in.close();
931c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                     if (out != null) out.close();
932c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                 } catch (IOException e) {}
933c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            }
934c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        }
935c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh
936c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        public void readAutoPairingData() {
937c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            if (mAutoPairingAddressBlacklist != null) return;
938c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            copyAutoPairingData();
939c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            FileInputStream fstream = null;
940c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            try {
941c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                fstream = new FileInputStream(DYNAMIC_AUTO_PAIRING_BLACKLIST);
942c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                DataInputStream in = new DataInputStream(fstream);
943c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                BufferedReader file = new BufferedReader(new InputStreamReader(in));
944c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                String line;
945c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                while((line = file.readLine()) != null) {
946c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    line = line.trim();
947c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    if (line.length() == 0 || line.startsWith("//")) continue;
948c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    String[] value = line.split("=");
949c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    if (value != null && value.length == 2) {
950c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        String[] val = value[1].split(",");
951c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        if (value[0].equalsIgnoreCase("AddressBlacklist")) {
952c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                            mAutoPairingAddressBlacklist =
953c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                                new ArrayList<String>(Arrays.asList(val));
954c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        } else if (value[0].equalsIgnoreCase("ExactNameBlacklist")) {
955c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                            mAutoPairingExactNameBlacklist =
956c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                                new ArrayList<String>(Arrays.asList(val));
957c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        } else if (value[0].equalsIgnoreCase("PartialNameBlacklist")) {
958c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                            mAutoPairingPartialNameBlacklist =
959c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                                new ArrayList<String>(Arrays.asList(val));
960c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        } else if (value[0].equalsIgnoreCase("DynamicAddressBlacklist")) {
961c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                            mAutoPairingDynamicAddressBlacklist =
962c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                                new ArrayList<String>(Arrays.asList(val));
963c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        } else {
964c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                            Log.e(TAG, "Error parsing Auto pairing blacklist file");
965c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        }
966c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    }
967c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                }
968c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            } catch (FileNotFoundException e) {
969c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                log("FileNotFoundException: readAutoPairingData" + e.toString());
970c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            } catch (IOException e) {
971c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                log("IOException: readAutoPairingData" + e.toString());
972c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            } finally {
973c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                if (fstream != null) {
974c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    try {
975c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        fstream.close();
976c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    } catch (IOException e) {
977c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        // Ignore
978c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    }
979c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                }
980c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            }
981c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        }
982c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh
983f51eadaf1f83abfe16a609a4ded6d789494689b2Jake Hamby        // This function adds a bluetooth address to the auto pairing blacklist
984c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        // file. These addresses are added to DynamicAddressBlacklistSection
985c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        private void updateAutoPairingData(String address) {
986c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            BufferedWriter out = null;
987c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            try {
988c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                out = new BufferedWriter(new FileWriter(DYNAMIC_AUTO_PAIRING_BLACKLIST, true));
989c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                StringBuilder str = new StringBuilder();
990c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                if (mAutoPairingDynamicAddressBlacklist.size() == 0) {
991c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    str.append("DynamicAddressBlacklist=");
992c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                }
993c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                str.append(address);
994c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                str.append(",");
995c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                out.write(str.toString());
996c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            } catch (FileNotFoundException e) {
997c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                log("FileNotFoundException: updateAutoPairingData" + e.toString());
998c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            } catch (IOException e) {
999c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                log("IOException: updateAutoPairingData" + e.toString());
1000c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            } finally {
1001c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                if (out != null) {
1002c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    try {
1003c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        out.close();
1004c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    } catch (IOException e) {
1005c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        // Ignore
1006c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    }
1007c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                }
1008c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            }
1009c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        }
10109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static String toBondStateString(int bondState) {
10139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        switch (bondState) {
1014005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        case BluetoothDevice.BOND_NONE:
10159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "not bonded";
10169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case BluetoothDevice.BOND_BONDING:
10179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "bonding";
10189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case BluetoothDevice.BOND_BONDED:
10199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "bonded";
10209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        default:
10219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "??????";
10229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10259519ce75f15ba287a641166c1b7ed10f2aa73f74Jaikumar Ganesh    /*package*/ synchronized boolean isAdapterPropertiesEmpty() {
10269519ce75f15ba287a641166c1b7ed10f2aa73f74Jaikumar Ganesh        return mAdapterProperties.isEmpty();
10279519ce75f15ba287a641166c1b7ed10f2aa73f74Jaikumar Ganesh    }
10289519ce75f15ba287a641166c1b7ed10f2aa73f74Jaikumar Ganesh
1029d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /*package*/synchronized void getAllProperties() {
10308c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
10319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1032bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mAdapterProperties.clear();
1033d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1034d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String properties[] = (String [])getAdapterPropertiesNative();
1035d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        // The String Array consists of key-value pairs.
1036d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (properties == null) {
1037d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            Log.e(TAG, "*Error*: GetAdapterProperties returned NULL");
1038d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return;
1039d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
1040d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
10418bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh        for (int i = 0; i < properties.length; i++) {
10428bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            String name = properties[i];
1043efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh            String newValue = null;
10448bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            int len;
10458bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            if (name == null) {
10468bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                Log.e(TAG, "Error:Adapter Property at index" + i + "is null");
10478bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                continue;
10488bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            }
10497a9de8b425954e4039053038e4ec1762b866c83cDanica Chang            if (name.equals("Devices") || name.equals("UUIDs")) {
1050efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                StringBuilder str = new StringBuilder();
10518bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                len = Integer.valueOf(properties[++i]);
10528bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                for (int j = 0; j < len; j++) {
1053efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                    str.append(properties[++i]);
1054efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                    str.append(",");
1055efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                }
1056efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                if (len > 0) {
1057efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                    newValue = str.toString();
10588bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                }
10598bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            } else {
10608bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                newValue = properties[++i];
10618bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            }
1062bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            mAdapterProperties.put(name, newValue);
1063d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
1064d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1065d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        // Add adapter object path property.
1066d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String adapterPath = getAdapterPathNative();
1067d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (adapterPath != null)
1068bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            mAdapterProperties.put("ObjectPath", adapterPath + "/dev_");
10699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1071d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ synchronized void setProperty(String name, String value) {
1072bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mAdapterProperties.put(name, value);
10739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean setName(String name) {
10769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
10779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
10789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (name == null) {
10799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
10809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1081d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setPropertyString("Name", name);
10829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1084d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    //TODO(): setPropertyString, setPropertyInteger, setPropertyBoolean
1085d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    // Either have a single property function with Object as the parameter
1086d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    // or have a function for each property and then obfuscate in the JNI layer.
1087d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    // The following looks dirty.
1088d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private boolean setPropertyString(String key, String value) {
10899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
10908c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
1091d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setAdapterPropertyStringNative(key, value);
10929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1094d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private boolean setPropertyInteger(String key, int value) {
1095d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
10968c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
1097d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setAdapterPropertyIntegerNative(key, value);
1098d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
10999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1100d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private boolean setPropertyBoolean(String key, boolean value) {
1101d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
11028c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
1103d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setAdapterPropertyBooleanNative(key, value ? 1 : 0);
11049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1106d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /**
1107d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Set the discoverability window for the device.  A timeout of zero
1108d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * makes the device permanently discoverable (if the device is
1109d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * discoverable).  Setting the timeout to a nonzero value does not make
1110d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * a device discoverable; you need to call setMode() to make the device
1111d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * explicitly discoverable.
1112d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     *
1113f51eadaf1f83abfe16a609a4ded6d789494689b2Jake Hamby     * @param timeout The discoverable timeout in seconds.
1114d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     */
1115d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized boolean setDiscoverableTimeout(int timeout) {
11169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
11179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
1118d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setPropertyInteger("DiscoverableTimeout", timeout);
11199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
112112835478ee687a493d1b5882e67b6725bd539c26Nick Pelly    public synchronized boolean setScanMode(int mode, int duration) {
112218b1e79a123b979d25bfa5d0b0ee5d0382dbd64bNick Pelly        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS,
112318b1e79a123b979d25bfa5d0b0ee5d0382dbd64bNick Pelly                                                "Need WRITE_SECURE_SETTINGS permission");
1124de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        boolean pairable = false;
1125de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        boolean discoverable = false;
112612835478ee687a493d1b5882e67b6725bd539c26Nick Pelly
1127de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        switch (mode) {
1128de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.SCAN_MODE_NONE:
112912835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            mHandler.removeMessages(MESSAGE_DISCOVERABLE_TIMEOUT);
1130d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            pairable = false;
1131d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            discoverable = false;
1132de893f550301a60274e87aa8168225e7a7a42184Nick Pelly            break;
1133de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
113412835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            mHandler.removeMessages(MESSAGE_DISCOVERABLE_TIMEOUT);
1135d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            pairable = true;
1136d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            discoverable = false;
1137005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            break;
1138de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
113912835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            mHandler.removeMessages(MESSAGE_DISCOVERABLE_TIMEOUT);
1140d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            pairable = true;
1141d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            discoverable = true;
114212835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            Message msg = mHandler.obtainMessage(MESSAGE_DISCOVERABLE_TIMEOUT);
114312835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            mHandler.sendMessageDelayed(msg, duration * 1000);
114412835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            if (DBG) Log.d(TAG, "BT Discoverable for " + duration + " seconds");
1145005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            break;
1146de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        default:
1147de893f550301a60274e87aa8168225e7a7a42184Nick Pelly            Log.w(TAG, "Requested invalid scan mode " + mode);
1148de893f550301a60274e87aa8168225e7a7a42184Nick Pelly            return false;
1149d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
1150d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        setPropertyBoolean("Pairable", pairable);
1151d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        setPropertyBoolean("Discoverable", discoverable);
11529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1153d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return true;
11549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1156b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh    /*package*/ synchronized String getProperty(String name) {
1157b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh        if (!isEnabledInternal()) return null;
1158b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh        return getPropertyInternal(name);
1159b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh    }
1160b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh
1161b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh    /*package*/ synchronized String getPropertyInternal(String name) {
1162bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        if (!mAdapterProperties.isEmpty())
1163bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            return mAdapterProperties.get(name);
1164d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        getAllProperties();
1165bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        return mAdapterProperties.get(name);
11669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1168d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized String getAddress() {
1169d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1170d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return getProperty("Address");
11719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1173d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized String getName() {
11749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1175d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return getProperty("Name");
11769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1179d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Returns the user-friendly name of a remote device.  This value is
1180d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * returned from our local cache, which is updated when onPropertyChange
1181d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * event is received.
1182d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Do not expect to retrieve the updated remote name immediately after
1183d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * changing the name on the remote device.
11849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1185d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * @param address Bluetooth address of remote device.
1186d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     *
1187d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * @return The user-friendly name of the specified remote device.
11889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1189d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized String getRemoteName(String address) {
1190d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1191005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1192d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return null;
1193d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
119455929a958bf0e482c8e4d7df3dd75957f1e9d871Jaikumar Ganesh        return getRemoteDeviceProperty(address, "Name");
11959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
11989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Get the discoverability window for the device.  A timeout of zero
11999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * means that the device is permanently discoverable (if the device is
12009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * in the discoverable mode).
12019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
12029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The discoverability window of the device, in seconds.  A negative
12039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         value indicates an error.
12049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
12059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized int getDiscoverableTimeout() {
12069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1207d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String timeout = getProperty("DiscoverableTimeout");
1208d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (timeout != null)
1209d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh           return Integer.valueOf(timeout);
1210d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        else
1211d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return -1;
12129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized int getScanMode() {
12159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
12168c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal())
1217de893f550301a60274e87aa8168225e7a7a42184Nick Pelly            return BluetoothAdapter.SCAN_MODE_NONE;
1218d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1219d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        boolean pairable = getProperty("Pairable").equals("true");
1220d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        boolean discoverable = getProperty("Discoverable").equals("true");
1221d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return bluezStringToScanMode (pairable, discoverable);
12229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1224d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized boolean startDiscovery() {
12259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
12269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
12278c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
12288c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1229d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return startDiscoveryNative();
12309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1232d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized boolean cancelDiscovery() {
12339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
12349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
12358c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
12368c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1237d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return stopDiscoveryNative();
1238d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
1239d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1240d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized boolean isDiscovering() {
1241d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1242d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return mIsDiscovering;
1243d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
1244d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1245d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ void setIsDiscovering(boolean isDiscovering) {
1246d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mIsDiscovering = isDiscovering;
12479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1249cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    private boolean isBondingFeasible(String address) {
12509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
12519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
12528c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
12538c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1254005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
12559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
12569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        address = address.toUpperCase();
12589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12592092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        if (mBondState.getPendingOutgoingBonding() != null) {
12609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            log("Ignoring createBond(): another device is bonding");
12619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // a different device is currently bonding, fail
12629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
12639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Check for bond state only if we are not performing auto
12669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // pairing exponential back-off attempts.
12679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mBondState.isAutoPairingAttemptsInProgress(address) &&
1268005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly                mBondState.getBondState(address) != BluetoothDevice.BOND_NONE) {
12699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            log("Ignoring createBond(): this device is already bonding or bonded");
12709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
12719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12733fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        if (address.equals(mDockAddress)) {
12743fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            if (!writeDockPin()) {
12753fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                log("Error while writing Pin for the dock");
12763fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                return false;
12773fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            }
12783fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        }
1279cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        return true;
1280cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    }
12813fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
1282cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    public synchronized boolean createBond(String address) {
1283cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (!isBondingFeasible(address)) return false;
1284cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
1285cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (!createPairedDeviceNative(address, 60000  /*1 minute*/ )) {
12869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
12879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12892092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        mBondState.setPendingOutgoingBonding(address);
12909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mBondState.setBondState(address, BluetoothDevice.BOND_BONDING);
12912092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
12929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
12939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1295cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    public synchronized boolean createBondOutOfBand(String address, byte[] hash,
1296cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh                                                    byte[] randomizer) {
1297cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (!isBondingFeasible(address)) return false;
12983fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
1299cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (!createPairedDeviceOutOfBandNative(address, 60000 /* 1 minute */)) {
13009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
13019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1303cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        setDeviceOutOfBandData(address, hash, randomizer);
13042092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        mBondState.setPendingOutgoingBonding(address);
13059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mBondState.setBondState(address, BluetoothDevice.BOND_BONDING);
13062092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
13079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
13089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1310cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    public synchronized boolean setDeviceOutOfBandData(String address, byte[] hash,
1311cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh            byte[] randomizer) {
1312cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1313cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh                                                "Need BLUETOOTH_ADMIN permission");
1314cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (!isEnabledInternal()) return false;
1315cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
1316cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        Pair <byte[], byte[]> value = new Pair<byte[], byte[]>(hash, randomizer);
1317cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
1318cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (DBG) {
1319cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh            log("Setting out of band data for:" + address + ":" +
1320cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh              Arrays.toString(hash) + ":" + Arrays.toString(randomizer));
1321cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        }
1322cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
1323cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        mDeviceOobData.put(address, value);
1324cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        return true;
1325cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    }
1326cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
1327cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    Pair<byte[], byte[]> getDeviceOutOfBandData(BluetoothDevice device) {
1328cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        return mDeviceOobData.get(device.getAddress());
1329cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    }
1330cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
1331cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
1332cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    public synchronized byte[] readOutOfBandData() {
1333cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
1334cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh                                                "Need BLUETOOTH permission");
1335cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (!isEnabledInternal()) return null;
1336cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
1337cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        return readAdapterOutOfBandDataNative();
1338cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    }
1339cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
13409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean cancelBondProcess(String address) {
13419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
13429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
13438c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
13448c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1345005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
13469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
13479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        address = address.toUpperCase();
13499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mBondState.getBondState(address) != BluetoothDevice.BOND_BONDING) {
13509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
13519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1353005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        mBondState.setBondState(address, BluetoothDevice.BOND_NONE,
13549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
1355d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        cancelDeviceCreationNative(address);
13569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
13579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean removeBond(String address) {
13609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
13619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
13628c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
13638c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1364005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
13659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
13669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1367f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
13689b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (state != null) {
1369f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            state.sendMessage(BluetoothDeviceProfileState.UNPAIR);
13709b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            return true;
13719b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        } else {
13729b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            return false;
13739b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
13749b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
13759b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
13769b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public synchronized boolean removeBondInternal(String address) {
1377d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return removeDeviceNative(getObjectPathFromAddress(address));
13789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized String[] listBonds() {
13819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
13829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mBondState.listInState(BluetoothDevice.BOND_BONDED);
13839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1385a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    /*package*/ synchronized String[] listInState(int state) {
1386a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh      return mBondState.listInState(state);
1387a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    }
1388a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh
13899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized int getBondState(String address) {
13909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1391005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1392b24e11baac589fe16426f2d243b460ab84991c7bNick Pelly            return BluetoothDevice.ERROR;
13939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mBondState.getBondState(address.toUpperCase());
13959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1397a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    /*package*/ synchronized boolean setBondState(String address, int state) {
1398a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        return setBondState(address, state, 0);
1399a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    }
1400a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh
1401a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    /*package*/ synchronized boolean setBondState(String address, int state, int reason) {
1402a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        mBondState.setBondState(address.toUpperCase(), state);
1403a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        return true;
1404a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    }
1405a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh
14063fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    public synchronized boolean isBluetoothDock(String address) {
14076e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh        SharedPreferences sp = mContext.getSharedPreferences(SHARED_PREFERENCES_NAME,
14086e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                mContext.MODE_PRIVATE);
14096e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh
14106e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh        return sp.contains(SHARED_PREFERENCE_DOCK_ADDRESS + address);
14113fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    }
14123fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
14136fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang    public synchronized boolean isTetheringOn() {
14146fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        return mTetheringOn;
14156fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang    }
14166fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang
1417707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh    /*package*/ synchronized boolean allowIncomingTethering() {
1418707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh        if (isTetheringOn() && getConnectedPanDevices().length < mMaxPanDevices)
1419707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh            return true;
1420707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh        return false;
1421707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh    }
1422707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh
14238aac82a5248e922bac2f84df746b5d1f34498f53Danica Chang    private BroadcastReceiver mTetheringReceiver = null;
14248aac82a5248e922bac2f84df746b5d1f34498f53Danica Chang
1425b70765cc27a174d1d4a0bab7062733ebd3eae354Jaikumar Ganesh    public synchronized void setBluetoothTethering(boolean value) {
14266fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        if (!value) {
14276fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang            disconnectPan();
14286fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        }
14298aac82a5248e922bac2f84df746b5d1f34498f53Danica Chang
1430b70765cc27a174d1d4a0bab7062733ebd3eae354Jaikumar Ganesh        if (getBluetoothState() != BluetoothAdapter.STATE_ON && value) {
14318aac82a5248e922bac2f84df746b5d1f34498f53Danica Chang            IntentFilter filter = new IntentFilter();
14328aac82a5248e922bac2f84df746b5d1f34498f53Danica Chang            filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
14338aac82a5248e922bac2f84df746b5d1f34498f53Danica Chang            mTetheringReceiver = new BroadcastReceiver() {
14348aac82a5248e922bac2f84df746b5d1f34498f53Danica Chang                @Override
14358aac82a5248e922bac2f84df746b5d1f34498f53Danica Chang                public synchronized void onReceive(Context context, Intent intent) {
14368aac82a5248e922bac2f84df746b5d1f34498f53Danica Chang                    if (intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.STATE_OFF)
14378aac82a5248e922bac2f84df746b5d1f34498f53Danica Chang                            == BluetoothAdapter.STATE_ON) {
1438b70765cc27a174d1d4a0bab7062733ebd3eae354Jaikumar Ganesh                        mTetheringOn = true;
14398aac82a5248e922bac2f84df746b5d1f34498f53Danica Chang                        mContext.unregisterReceiver(mTetheringReceiver);
14408aac82a5248e922bac2f84df746b5d1f34498f53Danica Chang                    }
14418aac82a5248e922bac2f84df746b5d1f34498f53Danica Chang                }
14428aac82a5248e922bac2f84df746b5d1f34498f53Danica Chang            };
14438aac82a5248e922bac2f84df746b5d1f34498f53Danica Chang            mContext.registerReceiver(mTetheringReceiver, filter);
14448aac82a5248e922bac2f84df746b5d1f34498f53Danica Chang        } else {
1445b70765cc27a174d1d4a0bab7062733ebd3eae354Jaikumar Ganesh            mTetheringOn = value;
14468aac82a5248e922bac2f84df746b5d1f34498f53Danica Chang        }
14476fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang    }
14486fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang
14496fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang    public synchronized int getPanDeviceState(BluetoothDevice device) {
14506fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
14516fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang
1452707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh        Pair<Integer, String> panDevice = mPanDevices.get(device);
1453707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh        if (panDevice == null) {
14546fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang            return BluetoothPan.STATE_DISCONNECTED;
14556fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        }
1456707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh        return panDevice.first;
14576fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang    }
14586fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang
14596fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang    public synchronized boolean connectPanDevice(BluetoothDevice device) {
14606fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
14616fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang                                                "Need BLUETOOTH_ADMIN permission");
14626fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang
14636fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        String objectPath = getObjectPathFromAddress(device.getAddress());
14646fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        if (DBG) log("connect PAN(" + objectPath + ")");
14656fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        if (getPanDeviceState(device) != BluetoothPan.STATE_DISCONNECTED) {
14666fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang            log (device + " already connected to PAN");
14676fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        }
14686fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang
14696fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        int connectedCount = 0;
1470707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh        for (BluetoothDevice panDevice: mPanDevices.keySet()) {
1471707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh            if (getPanDeviceState(panDevice) == BluetoothPan.STATE_CONNECTED) {
14726fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang                connectedCount ++;
14736fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang            }
14746fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        }
14756fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        if (connectedCount > 8) {
14766fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang            log (device + " could not connect to PAN because 8 other devices are already connected");
14776fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang            return false;
14786fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        }
14796fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang
14806fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        handlePanDeviceStateChange(device, BluetoothPan.STATE_CONNECTING);
14816fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        if (connectPanDeviceNative(objectPath, "nap", "panu")) {
14826fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang            log ("connecting to PAN");
14836fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang            return true;
14846fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        } else {
14856fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang            handlePanDeviceStateChange(device, BluetoothPan.STATE_DISCONNECTED);
14866fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang            log ("could not connect to PAN");
14876fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang            return false;
14886fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        }
14896fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang    }
14906fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang
14916fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang    private synchronized boolean disconnectPan() {
14926fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
14936fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        if (DBG) log("disconnect all PAN devices");
14946fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang
14956fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        for (BluetoothDevice device: mPanDevices.keySet()) {
14966fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang            if (getPanDeviceState(device) == BluetoothPan.STATE_CONNECTED) {
14976fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang                if (!disconnectPanDevice(device)) {
14986fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang                    log ("could not disconnect Pan Device "+device.getAddress());
14996fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang                    return false;
15006fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang                }
15016fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang            }
15026fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        }
15036fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        return true;
15046fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang    }
15056fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang
15066fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang    public synchronized BluetoothDevice[] getConnectedPanDevices() {
15076fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
15086fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang
15096fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        Set<BluetoothDevice> devices = new HashSet<BluetoothDevice>();
15106fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        for (BluetoothDevice device: mPanDevices.keySet()) {
15116fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang            if (getPanDeviceState(device) == BluetoothPan.STATE_CONNECTED) {
15126fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang                devices.add(device);
15136fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang            }
15146fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        }
15156fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        return devices.toArray(new BluetoothDevice[devices.size()]);
15166fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang    }
15176fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang
15186fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang    public synchronized boolean disconnectPanDevice(BluetoothDevice device) {
15196fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
15206fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang                                                "Need BLUETOOTH_ADMIN permission");
15216fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        String objectPath = getObjectPathFromAddress(device.getAddress());
15226fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        if (DBG) log("disconnect PAN(" + objectPath + ")");
15236fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        if (getPanDeviceState(device) != BluetoothPan.STATE_CONNECTED) {
15246fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang            log (device + " already disconnected from PAN");
15256fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        }
15266fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        handlePanDeviceStateChange(device, BluetoothPan.STATE_DISCONNECTING);
15276fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        return disconnectPanDeviceNative(objectPath);
15286fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang    }
15296fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang
1530707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh    /*package*/ synchronized void handlePanDeviceStateChange(BluetoothDevice device,
1531707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh                                                             String iface,
1532707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh                                                             int state) {
15336fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        int prevState;
1534707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh        String ifaceAddr = null;
1535707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh
15366fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        if (mPanDevices.get(device) == null) {
15376fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang            prevState = BluetoothPan.STATE_DISCONNECTED;
15386fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        } else {
1539707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh            prevState = mPanDevices.get(device).first;
1540707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh            ifaceAddr = mPanDevices.get(device).second;
15416fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        }
15426fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        if (prevState == state) return;
15436fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang
15446fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        if (state == BluetoothPan.STATE_CONNECTED) {
1545707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh            ifaceAddr = enableTethering(iface);
1546707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh            if (ifaceAddr == null) Log.e(TAG, "Error seting up tether interface");
1547707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh        } else if (state == BluetoothPan.STATE_DISCONNECTED) {
1548707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh            if (ifaceAddr != null) {
1549707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh                mBluetoothIfaceAddresses.remove(ifaceAddr);
1550707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh                ifaceAddr = null;
1551707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh            }
15526fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        }
15536fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang
1554707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh        Pair<Integer, String> value = new Pair<Integer, String>(state, ifaceAddr);
1555707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh        mPanDevices.put(device, value);
1556707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh
15576fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        Intent intent = new Intent(BluetoothPan.ACTION_PAN_STATE_CHANGED);
15586fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
15596fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        intent.putExtra(BluetoothPan.EXTRA_PREVIOUS_PAN_STATE, prevState);
15606fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        intent.putExtra(BluetoothPan.EXTRA_PAN_STATE, state);
15616fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        mContext.sendBroadcast(intent, BLUETOOTH_PERM);
15626fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang
15636fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        if (DBG) log("Pan Device state : device: " + device + " State:" + prevState + "->" + state);
1564707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh    }
1565707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh
1566707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh    /*package*/ synchronized void handlePanDeviceStateChange(BluetoothDevice device,
1567707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh                                                             int state) {
1568707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh        handlePanDeviceStateChange(device, null, state);
1569707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh    }
15706fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang
1571707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh    private String createNewTetheringAddressLocked() {
1572707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh        if (getConnectedPanDevices().length == mMaxPanDevices) {
1573707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh            log("Max PAN device connections reached");
1574707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh            return null;
1575707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh        }
1576707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh        String address = BLUETOOTH_IFACE_ADDR_START;
1577707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh        while (true) {
1578707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh            if (mBluetoothIfaceAddresses.contains(address)) {
1579707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh                String[] addr = address.split("\\.");
1580707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh                Integer newIp = Integer.parseInt(addr[2]) + 1;
1581707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh                address = address.replace(addr[2], newIp.toString());
1582707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh            } else {
1583707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh                break;
1584707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh            }
1585707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh        }
1586707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh        mBluetoothIfaceAddresses.add(address);
1587707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh        return address;
15886fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang    }
15896fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang
1590707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh    // configured when we start tethering
1591707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh    private synchronized String enableTethering(String iface) {
1592707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh        log("updateTetherState:" + iface);
15936fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang
15946fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
15956fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
15966fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        ConnectivityManager cm =
15976fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang            (ConnectivityManager)mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
15986fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        String[] bluetoothRegexs = cm.getTetherableBluetoothRegexs();
15996fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang
16006fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        // bring toggle the interfaces
1601707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh        String[] currentIfaces = new String[0];
16026fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        try {
1603707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh            currentIfaces = service.listInterfaces();
16046fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        } catch (Exception e) {
16056fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang            Log.e(TAG, "Error listing Interfaces :" + e);
1606707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh            return null;
16076fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        }
16086fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang
1609707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh        boolean found = false;
1610707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh        for (String currIface: currentIfaces) {
1611707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh            if (currIface.equals(iface)) {
1612707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh                found = true;
1613707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh                break;
16146fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang            }
16156fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        }
16166fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang
1617707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh        if (!found) return null;
1618707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh
1619707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh        String address = createNewTetheringAddressLocked();
1620707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh        if (address == null) return null;
1621707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh
1622707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh        InterfaceConfiguration ifcg = null;
1623707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh        try {
1624707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh            ifcg = service.getInterfaceConfig(iface);
1625707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh            if (ifcg != null) {
1626707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh                String[] addr = BLUETOOTH_NETMASK.split("\\.");
1627707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh                ifcg.netmask = (Integer.parseInt(addr[0]) << 24) +
1628707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh                        (Integer.parseInt(addr[1]) << 16) +
1629707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh                        (Integer.parseInt(addr[2]) << 8) +
1630707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh                        (Integer.parseInt(addr[3]));
1631707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh                if (ifcg.ipAddr == 0) {
1632707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh                    addr = address.split("\\.");
1633707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh
1634707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh                    ifcg.ipAddr = (Integer.parseInt(addr[0]) << 24) +
1635707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh                            (Integer.parseInt(addr[1]) << 16) +
1636707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh                            (Integer.parseInt(addr[2]) << 8) +
1637707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh                            (Integer.parseInt(addr[3]));
1638707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh                    ifcg.interfaceFlags =
1639707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh                        ifcg.interfaceFlags.replace("down", "up");
1640707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh                }
1641707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh                ifcg.interfaceFlags = ifcg.interfaceFlags.replace("running", "");
1642707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh                ifcg.interfaceFlags = ifcg.interfaceFlags.replace("  "," ");
1643707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh                service.setInterfaceConfig(iface, ifcg);
1644707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh                if (cm.tether(iface) != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
1645707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh                    Log.e(TAG, "Error tethering "+iface);
1646707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh                }
1647707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh            }
1648707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh        } catch (Exception e) {
1649707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh            Log.e(TAG, "Error configuring interface " + iface + ", :" + e);
1650707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh            return null;
1651707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh        }
1652707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh        return address;
16536fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang    }
16546fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang
1655545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh    public synchronized boolean connectInputDevice(BluetoothDevice device) {
1656545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1657545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh                                                "Need BLUETOOTH_ADMIN permission");
1658545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh
1659545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        String objectPath = getObjectPathFromAddress(device.getAddress());
166005a1863cebcc8e318283f3f4a49ba69d83b62866Jaikumar Ganesh        if (objectPath == null ||
166105a1863cebcc8e318283f3f4a49ba69d83b62866Jaikumar Ganesh            getInputDeviceState(device) != BluetoothInputDevice.STATE_DISCONNECTED ||
1662545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh            getInputDevicePriority(device) == BluetoothInputDevice.PRIORITY_OFF) {
1663545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh            return false;
1664545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        }
1665de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh        BluetoothDeviceProfileState state = mDeviceProfileState.get(device.getAddress());
1666de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh        if (state != null) {
1667de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh            Message msg = new Message();
1668de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh            msg.arg1 = BluetoothDeviceProfileState.CONNECT_HID_OUTGOING;
1669de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh            msg.obj = state;
1670de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh            mHidProfileState.sendMessage(msg);
1671545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh            return true;
1672545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        }
1673545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        return false;
1674545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh    }
1675545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh
1676de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh    public synchronized boolean connectInputDeviceInternal(BluetoothDevice device) {
1677de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh        String objectPath = getObjectPathFromAddress(device.getAddress());
1678de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh        handleInputDeviceStateChange(device, BluetoothInputDevice.STATE_CONNECTING);
1679de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh        if (!connectInputDeviceNative(objectPath)) {
1680de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh            handleInputDeviceStateChange(device, BluetoothInputDevice.STATE_DISCONNECTED);
1681de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh            return false;
1682de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh        }
1683de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh        return true;
1684de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh    }
1685de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh
1686545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh    public synchronized boolean disconnectInputDevice(BluetoothDevice device) {
1687545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1688545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh                                                "Need BLUETOOTH_ADMIN permission");
1689545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh
1690545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        String objectPath = getObjectPathFromAddress(device.getAddress());
1691545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        if (objectPath == null || getConnectedInputDevices().length == 0) {
1692545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh            return false;
1693545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        }
1694de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh        BluetoothDeviceProfileState state = mDeviceProfileState.get(device.getAddress());
1695de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh        if (state != null) {
1696de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh            Message msg = new Message();
1697de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh            msg.arg1 = BluetoothDeviceProfileState.DISCONNECT_HID_OUTGOING;
1698de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh            msg.obj = state;
1699de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh            mHidProfileState.sendMessage(msg);
1700545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh            return true;
1701545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        }
1702545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        return false;
1703545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh    }
1704545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh
1705de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh    public synchronized boolean disconnectInputDeviceInternal(BluetoothDevice device) {
1706de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh        String objectPath = getObjectPathFromAddress(device.getAddress());
1707de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh        handleInputDeviceStateChange(device, BluetoothInputDevice.STATE_DISCONNECTING);
1708de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh        if (!disconnectInputDeviceNative(objectPath)) {
1709de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh            handleInputDeviceStateChange(device, BluetoothInputDevice.STATE_CONNECTED);
1710de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh            return false;
1711de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh        }
1712de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh        return true;
1713de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh    }
1714de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh
1715545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh    public synchronized int getInputDeviceState(BluetoothDevice device) {
1716545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1717545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh
1718545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        if (mInputDevices.get(device) == null) {
1719545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh            return BluetoothInputDevice.STATE_DISCONNECTED;
1720545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        }
1721df7627db715a7a2e7f646f02a07caf2347bb90b8Adam Powell        return mInputDevices.get(device);
1722545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh    }
1723545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh
1724545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh    public synchronized BluetoothDevice[] getConnectedInputDevices() {
1725545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1726545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        Set<BluetoothDevice> devices = lookupInputDevicesMatchingStates(
1727545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh            new int[] {BluetoothInputDevice.STATE_CONNECTED});
1728545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        return devices.toArray(new BluetoothDevice[devices.size()]);
1729545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh    }
1730545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh
1731545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh    public synchronized int getInputDevicePriority(BluetoothDevice device) {
1732545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1733545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        return Settings.Secure.getInt(mContext.getContentResolver(),
1734545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh                Settings.Secure.getBluetoothInputDevicePriorityKey(device.getAddress()),
1735545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh                BluetoothInputDevice.PRIORITY_UNDEFINED);
1736545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh    }
1737545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh
1738545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh    public synchronized boolean setInputDevicePriority(BluetoothDevice device, int priority) {
1739545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1740545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh                                                "Need BLUETOOTH_ADMIN permission");
1741545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        if (!BluetoothAdapter.checkBluetoothAddress(device.getAddress())) {
1742545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh            return false;
1743545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        }
1744545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        return Settings.Secure.putInt(mContext.getContentResolver(),
1745545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh                Settings.Secure.getBluetoothInputDevicePriorityKey(device.getAddress()),
1746545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh                priority);
1747545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh    }
1748545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh
1749545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh    /*package*/synchronized Set<BluetoothDevice> lookupInputDevicesMatchingStates(int[] states) {
1750545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        Set<BluetoothDevice> inputDevices = new HashSet<BluetoothDevice>();
1751545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        if (mInputDevices.isEmpty()) {
1752545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh            return inputDevices;
1753545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        }
1754545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        for (BluetoothDevice device: mInputDevices.keySet()) {
1755545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh            int inputDeviceState = getInputDeviceState(device);
1756545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh            for (int state : states) {
1757545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh                if (state == inputDeviceState) {
1758545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh                    inputDevices.add(device);
1759545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh                    break;
1760545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh                }
1761545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh            }
1762545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        }
1763545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        return inputDevices;
1764545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh    }
1765545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh
1766545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh    private synchronized void handleInputDeviceStateChange(BluetoothDevice device, int state) {
1767545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        int prevState;
1768545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        if (mInputDevices.get(device) == null) {
1769545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh            prevState = BluetoothInputDevice.STATE_DISCONNECTED;
1770545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        } else {
1771545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh            prevState = mInputDevices.get(device);
1772545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        }
1773545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        if (prevState == state) return;
1774545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh
1775545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        mInputDevices.put(device, state);
1776545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh
1777545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        if (getInputDevicePriority(device) >
1778545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh              BluetoothInputDevice.PRIORITY_OFF &&
1779545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh            state == BluetoothInputDevice.STATE_CONNECTING ||
1780545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh            state == BluetoothInputDevice.STATE_CONNECTED) {
1781545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh            // We have connected or attempting to connect.
1782545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh            // Bump priority
1783545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh            setInputDevicePriority(device, BluetoothInputDevice.PRIORITY_AUTO_CONNECT);
1784545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        }
1785545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh
1786545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        Intent intent = new Intent(BluetoothInputDevice.ACTION_INPUT_DEVICE_STATE_CHANGED);
1787545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
1788545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        intent.putExtra(BluetoothInputDevice.EXTRA_PREVIOUS_INPUT_DEVICE_STATE, prevState);
1789545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        intent.putExtra(BluetoothInputDevice.EXTRA_INPUT_DEVICE_STATE, state);
1790545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        mContext.sendBroadcast(intent, BLUETOOTH_PERM);
1791545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh
1792545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        if (DBG) log("InputDevice state : device: " + device + " State:" + prevState + "->" + state);
1793545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh
1794545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh    }
1795545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh
179656d26139659c2414d289194c63860ff27ab80da0Jaikumar Ganesh    /*package*/ void handleInputDevicePropertyChange(String address, boolean connected) {
1797545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        int state = connected ? BluetoothInputDevice.STATE_CONNECTED :
1798545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh            BluetoothInputDevice.STATE_DISCONNECTED;
1799545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        BluetoothDevice device = mAdapter.getRemoteDevice(address);
1800545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        handleInputDeviceStateChange(device, state);
1801545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh    }
1802545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh
1803c3ee99d9eb7e8b4b20c2b8f1c548373e1017e0d3Jaikumar Ganesh    private void setInitialInputDevicePriority(BluetoothDevice device, int state) {
1804c3ee99d9eb7e8b4b20c2b8f1c548373e1017e0d3Jaikumar Ganesh        switch (state) {
1805c3ee99d9eb7e8b4b20c2b8f1c548373e1017e0d3Jaikumar Ganesh            case BluetoothDevice.BOND_BONDED:
1806c3ee99d9eb7e8b4b20c2b8f1c548373e1017e0d3Jaikumar Ganesh                if (getInputDevicePriority(device) == BluetoothInputDevice.PRIORITY_UNDEFINED) {
1807c3ee99d9eb7e8b4b20c2b8f1c548373e1017e0d3Jaikumar Ganesh                    setInputDevicePriority(device, BluetoothInputDevice.PRIORITY_ON);
1808c3ee99d9eb7e8b4b20c2b8f1c548373e1017e0d3Jaikumar Ganesh                }
1809c3ee99d9eb7e8b4b20c2b8f1c548373e1017e0d3Jaikumar Ganesh                break;
1810c3ee99d9eb7e8b4b20c2b8f1c548373e1017e0d3Jaikumar Ganesh            case BluetoothDevice.BOND_NONE:
1811c3ee99d9eb7e8b4b20c2b8f1c548373e1017e0d3Jaikumar Ganesh                setInputDevicePriority(device, BluetoothInputDevice.PRIORITY_UNDEFINED);
1812c3ee99d9eb7e8b4b20c2b8f1c548373e1017e0d3Jaikumar Ganesh                break;
1813c3ee99d9eb7e8b4b20c2b8f1c548373e1017e0d3Jaikumar Ganesh        }
1814c3ee99d9eb7e8b4b20c2b8f1c548373e1017e0d3Jaikumar Ganesh    }
1815c3ee99d9eb7e8b4b20c2b8f1c548373e1017e0d3Jaikumar Ganesh
18169488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh    /*package*/ boolean isRemoteDeviceInCache(String address) {
1817bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        return (mDeviceProperties.get(address) != null);
18189488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh    }
18199488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh
18209488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh    /*package*/ String[] getRemoteDeviceProperties(String address) {
18218c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return null;
18228c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
18239488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh        String objectPath = getObjectPathFromAddress(address);
18249488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh        return (String [])getDevicePropertiesNative(objectPath);
18259488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh    }
18269488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh
1827d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /*package*/ synchronized String getRemoteDeviceProperty(String address, String property) {
1828bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        Map<String, String> properties = mDeviceProperties.get(address);
1829d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (properties != null) {
1830d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return properties.get(property);
1831d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        } else {
1832d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            // Query for remote device properties, again.
1833d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            // We will need to reload the cache when we switch Bluetooth on / off
1834d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            // or if we crash.
183510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            if (updateRemoteDevicePropertiesCache(address))
1836d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                return getRemoteDeviceProperty(address, property);
18379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
18386fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang        Log.e(TAG, "getRemoteDeviceProperty: " + property + " not present: " + address);
1839d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return null;
18409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
18419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
184210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh    /* package */ synchronized boolean updateRemoteDevicePropertiesCache(String address) {
184310eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        String[] propValues = getRemoteDeviceProperties(address);
184410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        if (propValues != null) {
184510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            addRemoteDeviceProperties(address, propValues);
184610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            return true;
184710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        }
184810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        return false;
184910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh    }
185010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
1851d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ synchronized void addRemoteDeviceProperties(String address, String[] properties) {
1852395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh        /*
1853395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh         * We get a DeviceFound signal every time RSSI changes or name changes.
1854395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh         * Don't create a new Map object every time */
1855bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        Map<String, String> propertyValues = mDeviceProperties.get(address);
1856efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh        if (propertyValues == null) {
1857395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh            propertyValues = new HashMap<String, String>();
1858395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh        }
1859395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh
18608bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh        for (int i = 0; i < properties.length; i++) {
18618bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            String name = properties[i];
1862efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh            String newValue = null;
18638bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            int len;
18648bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            if (name == null) {
18658bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                Log.e(TAG, "Error: Remote Device Property at index" + i + "is null");
18668bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                continue;
18678bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            }
18688bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            if (name.equals("UUIDs") || name.equals("Nodes")) {
1869efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                StringBuilder str = new StringBuilder();
18708bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                len = Integer.valueOf(properties[++i]);
18718bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                for (int j = 0; j < len; j++) {
1872efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                    str.append(properties[++i]);
1873efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                    str.append(",");
1874efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                }
1875efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                if (len > 0) {
1876efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                    newValue = str.toString();
18778bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                }
1878d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            } else {
18798bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                newValue = properties[++i];
1880d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            }
1881efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh
18828bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            propertyValues.put(name, newValue);
18839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1884bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mDeviceProperties.put(address, propertyValues);
188510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
188610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        // We have added a new remote device or updated its properties.
188710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        // Also update the serviceChannel cache.
188810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        updateDeviceServiceChannelCache(address);
18899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
18909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1891d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ void removeRemoteDeviceProperties(String address) {
1892bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mDeviceProperties.remove(address);
18939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
18949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1895d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ synchronized void setRemoteDeviceProperty(String address, String name,
1896d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                                                              String value) {
1897bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        Map <String, String> propVal = mDeviceProperties.get(address);
1898d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (propVal != null) {
1899d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            propVal.put(name, value);
1900bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            mDeviceProperties.put(address, propVal);
1901d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        } else {
1902d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            Log.e(TAG, "setRemoteDeviceProperty for a device not in cache:" + address);
19039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
19049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
19059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1907efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * Sets the remote device trust state.
1908efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     *
1909efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * @return boolean to indicate operation success or fail
1910efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     */
1911efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    public synchronized boolean setTrust(String address, boolean value) {
1912005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1913e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly            mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1914e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly                    "Need BLUETOOTH_ADMIN permission");
1915efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            return false;
1916efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        }
1917efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue
19188c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
19198c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1920efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        return setDevicePropertyBooleanNative(getObjectPathFromAddress(address), "Trusted",
1921efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue                value ? 1 : 0);
1922efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    }
1923efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue
1924efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    /**
1925efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * Gets the remote device trust state as boolean.
1926efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * Note: this value may be
1927efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * retrieved from cache if we retrieved the data before *
1928efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     *
1929efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * @return boolean to indicate trust or untrust state
1930efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     */
1931efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    public synchronized boolean getTrustState(String address) {
1932005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1933efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1934efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            return false;
1935efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        }
1936efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue
1937efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        String val = getRemoteDeviceProperty(address, "Trusted");
1938efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        if (val == null) {
1939efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            return false;
1940efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        } else {
1941efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            return val.equals("true") ? true : false;
1942efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        }
1943efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    }
1944efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue
1945efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    /**
1946d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Gets the remote major, minor classes encoded as a 32-bit
19479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * integer.
19489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
19499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Note: this value is retrieved from cache, because we get it during
19509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *       remote-device discovery.
19519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
19529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return 32-bit integer encoding the remote major, minor, and service
19539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         classes.
19549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
19559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized int getRemoteClass(String address) {
1956005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1957ea600ccfb7568f60377c4abc85f56c80af7fdbfcNick Pelly            mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1958ea600ccfb7568f60377c4abc85f56c80af7fdbfcNick Pelly            return BluetoothClass.ERROR;
19599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1960d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String val = getRemoteDeviceProperty(address, "Class");
1961d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (val == null)
1962d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return BluetoothClass.ERROR;
1963d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        else {
1964d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return Integer.valueOf(val);
1965d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
19669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1967d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
19689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1970dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh     * Gets the UUIDs supported by the remote device
19719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1972dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh     * @return array of 128bit ParcelUuids
19739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1974dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh    public synchronized ParcelUuid[] getRemoteUuids(String address) {
19759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1976005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
19779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return null;
19789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
19791caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        return getUuidFromCache(address);
19801caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    }
19811caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
19821caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    private ParcelUuid[] getUuidFromCache(String address) {
1983d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String value = getRemoteDeviceProperty(address, "UUIDs");
1984dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        if (value == null) return null;
1985dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh
1986dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        String[] uuidStrings = null;
1987d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        // The UUIDs are stored as a "," separated string.
1988dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        uuidStrings = value.split(",");
1989dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        ParcelUuid[] uuids = new ParcelUuid[uuidStrings.length];
1990dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh
1991dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        for (int i = 0; i < uuidStrings.length; i++) {
1992dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh            uuids[i] = ParcelUuid.fromString(uuidStrings[i]);
1993dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        }
1994d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return uuids;
19959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
19969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
199716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    /**
199816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * Connect and fetch new UUID's using SDP.
199916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * The UUID's found are broadcast as intents.
200016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * Optionally takes a uuid and callback to fetch the RFCOMM channel for the
200116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * a given uuid.
200216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * TODO: Don't wait UUID_INTENT_DELAY to broadcast UUID intents on success
200316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * TODO: Don't wait UUID_INTENT_DELAY to handle the failure case for
200416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * callback and broadcast intents.
200516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     */
200616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    public synchronized boolean fetchRemoteUuids(String address, ParcelUuid uuid,
200716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            IBluetoothCallback callback) {
20081caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
20098c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
20108c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
20111caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
20121caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            return false;
20131caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        }
20141caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
201516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        RemoteService service = new RemoteService(address, uuid);
201616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        if (uuid != null && mUuidCallbackTracker.get(service) != null) {
201716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            // An SDP query for this address & uuid is already in progress
201816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            // Do not add this callback for the uuid
201916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            return false;
202016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
202116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
20221caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        if (mUuidIntentTracker.contains(address)) {
20231caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            // An SDP query for this address is already in progress
202416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            // Add this uuid onto the in-progress SDP query
202516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (uuid != null) {
202616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                mUuidCallbackTracker.put(new RemoteService(address, uuid), callback);
202716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
20281caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            return true;
20291caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        }
20301caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
20311caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        boolean ret;
20320e09030977aea8b40fd177139528d4b5637c9771Jaikumar Ganesh        // Just do the SDP if the device is already  created and UUIDs are not
20330e09030977aea8b40fd177139528d4b5637c9771Jaikumar Ganesh        // NULL, else create the device and then do SDP.
20340e09030977aea8b40fd177139528d4b5637c9771Jaikumar Ganesh        if (isRemoteDeviceInCache(address) && getRemoteUuids(address) != null) {
20351caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            String path = getObjectPathFromAddress(address);
20361caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            if (path == null) return false;
20371caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
20381caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            // Use an empty string for the UUID pattern
20391caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            ret = discoverServicesNative(path, "");
20401caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        } else {
20411caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            ret = createDeviceNative(address);
20421caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        }
20431caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
20441caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        mUuidIntentTracker.add(address);
204516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        if (uuid != null) {
204616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            mUuidCallbackTracker.put(new RemoteService(address, uuid), callback);
204716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
20481caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
20491caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        Message message = mHandler.obtainMessage(MESSAGE_UUID_INTENT);
20501caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        message.obj = address;
20511caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        mHandler.sendMessageDelayed(message, UUID_INTENT_DELAY);
20521caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        return ret;
20531caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    }
20541caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
20559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2056d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Gets the rfcomm channel associated with the UUID.
205716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * Pulls records from the cache only.
20589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2059d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * @param address Address of the remote device
2060dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh     * @param uuid ParcelUuid of the service attribute
20619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2062d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * @return rfcomm channel associated with the service attribute
206310eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh     *         -1 on error
20649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2065dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh    public int getRemoteServiceChannel(String address, ParcelUuid uuid) {
20669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
20678c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return -1;
20688c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
2069005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
2070b24e11baac589fe16426f2d243b460ab84991c7bNick Pelly            return BluetoothDevice.ERROR;
20719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
207210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        // Check if we are recovering from a crash.
207310eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        if (mDeviceProperties.isEmpty()) {
207410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            if (!updateRemoteDevicePropertiesCache(address))
207510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh                return -1;
207610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        }
207710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
207810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        Map<ParcelUuid, Integer> value = mDeviceServiceChannelCache.get(address);
207910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        if (value != null && value.containsKey(uuid))
208010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            return value.get(uuid);
208110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        return -1;
20829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
20839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean setPin(String address, byte[] pin) {
20859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
20869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
20878c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
20888c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
20899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (pin == null || pin.length <= 0 || pin.length > 16 ||
2090005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            !BluetoothAdapter.checkBluetoothAddress(address)) {
20919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
20929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
20939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        address = address.toUpperCase();
20949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
20959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (data == null) {
20969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.w(TAG, "setPin(" + address + ") called but no native data available, " +
20979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                  "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
20989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                  " or by bluez.\n");
20999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
21009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
21019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // bluez API wants pin as a string
21029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String pinString;
21039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
21049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pinString = new String(pin, "UTF8");
21059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (UnsupportedEncodingException uee) {
21069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.e(TAG, "UTF8 not supported?!?");
21079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
21089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
21099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return setPinNative(address, pinString, data.intValue());
21109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
21119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2112b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    public synchronized boolean setPasskey(String address, int passkey) {
2113b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
2114b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                                                "Need BLUETOOTH_ADMIN permission");
21158c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
21168c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
2117005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (passkey < 0 || passkey > 999999 || !BluetoothAdapter.checkBluetoothAddress(address)) {
2118b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            return false;
2119b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        }
2120b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        address = address.toUpperCase();
2121b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
2122b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        if (data == null) {
2123b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            Log.w(TAG, "setPasskey(" + address + ") called but no native data available, " +
2124b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                  "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
2125b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                  " or by bluez.\n");
2126b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            return false;
2127b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        }
2128b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        return setPasskeyNative(address, passkey, data.intValue());
2129b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    }
2130b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh
2131b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    public synchronized boolean setPairingConfirmation(String address, boolean confirm) {
2132b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
2133b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                                                "Need BLUETOOTH_ADMIN permission");
21348c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
21358c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
2136b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        address = address.toUpperCase();
2137b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
2138b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        if (data == null) {
2139b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            Log.w(TAG, "setPasskey(" + address + ") called but no native data available, " +
2140b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                  "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
2141b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                  " or by bluez.\n");
2142b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            return false;
2143b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        }
2144b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        return setPairingConfirmationNative(address, confirm, data.intValue());
2145b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    }
2146b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh
2147cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    public synchronized boolean setRemoteOutOfBandData(String address) {
2148cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
2149cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh                                                "Need BLUETOOTH_ADMIN permission");
2150cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (!isEnabledInternal()) return false;
2151cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        address = address.toUpperCase();
2152cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
2153cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (data == null) {
2154cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh            Log.w(TAG, "setRemoteOobData(" + address + ") called but no native data available, " +
2155cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh                  "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
2156cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh                  " or by bluez.\n");
2157cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh            return false;
2158cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        }
2159cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
2160cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        Pair<byte[], byte[]> val = mDeviceOobData.get(address);
2161cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        byte[] hash, randomizer;
2162cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (val == null) {
2163cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh            // TODO: check what should be passed in this case.
2164cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh            hash = new byte[16];
2165cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh            randomizer = new byte[16];
2166cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        } else {
2167cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh            hash = val.first;
2168cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh            randomizer = val.second;
2169cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        }
2170cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        return setRemoteOutOfBandDataNative(address, hash, randomizer, data.intValue());
2171cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    }
2172cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
2173b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    public synchronized boolean cancelPairingUserInput(String address) {
21749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
21759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
21768c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
21778c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
2178005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
21799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
21809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2181005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        mBondState.setBondState(address, BluetoothDevice.BOND_NONE,
2182397d8f4f4829a45f4fe7a672cc395466bbc0f442Jaikumar Ganesh                BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
21839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        address = address.toUpperCase();
21849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
21859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (data == null) {
2186b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            Log.w(TAG, "cancelUserInputNative(" + address + ") called but no native data " +
2187b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                "available, ignoring. Maybe the PasskeyAgent Request was already cancelled " +
2188b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                "by the remote or by bluez.\n");
21899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
21909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2191b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        return cancelPairingUserInputNative(address, data.intValue());
21929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
21939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21948c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh    /*package*/ void updateDeviceServiceChannelCache(String address) {
219510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        ParcelUuid[] deviceUuids = getRemoteUuids(address);
219610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        // We are storing the rfcomm channel numbers only for the uuids
219710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        // we are interested in.
219810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        int channel;
219916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        if (DBG) log("updateDeviceServiceChannelCache(" + address + ")");
220016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
220116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        ArrayList<ParcelUuid> applicationUuids = new ArrayList();
220216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
220316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        synchronized (this) {
220416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            for (RemoteService service : mUuidCallbackTracker.keySet()) {
220516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (service.address.equals(address)) {
220616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    applicationUuids.add(service.uuid);
220716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                }
220816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
220916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
221010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
221110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        Map <ParcelUuid, Integer> value = new HashMap<ParcelUuid, Integer>();
221216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
221316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        // Retrieve RFCOMM channel for default uuids
221416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        for (ParcelUuid uuid : RFCOMM_UUIDS) {
221510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            if (BluetoothUuid.isUuidPresent(deviceUuids, uuid)) {
221616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                channel = getDeviceServiceChannelNative(getObjectPathFromAddress(address),
221716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        uuid.toString(), 0x0004);
221816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (DBG) log("\tuuid(system): " + uuid + " " + channel);
221910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh                value.put(uuid, channel);
222010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            }
222110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        }
222216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        // Retrieve RFCOMM channel for application requested uuids
222316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        for (ParcelUuid uuid : applicationUuids) {
222416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (BluetoothUuid.isUuidPresent(deviceUuids, uuid)) {
222516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                channel = getDeviceServiceChannelNative(getObjectPathFromAddress(address),
222616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        uuid.toString(), 0x0004);
222716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (DBG) log("\tuuid(application): " + uuid + " " + channel);
222816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                value.put(uuid, channel);
222916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
223016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
223116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
223216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        synchronized (this) {
223316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            // Make application callbacks
223416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            for (Iterator<RemoteService> iter = mUuidCallbackTracker.keySet().iterator();
223516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    iter.hasNext();) {
223616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                RemoteService service = iter.next();
223716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (service.address.equals(address)) {
223816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    channel = -1;
223916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    if (value.get(service.uuid) != null) {
224016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        channel = value.get(service.uuid);
224116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    }
224216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    if (channel != -1) {
224316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        if (DBG) log("Making callback for " + service.uuid + " with result " +
224416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                                channel);
224516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        IBluetoothCallback callback = mUuidCallbackTracker.get(service);
224616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        if (callback != null) {
224716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                            try {
224816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                                callback.onRfcommChannelFound(channel);
224916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                            } catch (RemoteException e) {Log.e(TAG, "", e);}
225016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        }
225116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
225216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        iter.remove();
225316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    }
225416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                }
225516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
225616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
225716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            // Update cache
225816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            mDeviceServiceChannelCache.put(address, value);
225916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
226010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh    }
226110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
226224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    /**
226324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     * b is a handle to a Binder instance, so that this service can be notified
226424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     * for Applications that terminate unexpectedly, to clean there service
226524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     * records
226624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     */
226724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    public synchronized int addRfcommServiceRecord(String serviceName, ParcelUuid uuid,
226824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            int channel, IBinder b) {
22698c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
22708c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return -1;
22718c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
227224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (serviceName == null || uuid == null || channel < 1 ||
227324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                channel > BluetoothSocket.MAX_RFCOMM_CHANNEL) {
227424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            return -1;
227524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
227624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (BluetoothUuid.isUuidPresent(BluetoothUuid.RESERVED_UUIDS, uuid)) {
227724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            Log.w(TAG, "Attempted to register a reserved UUID: " + uuid);
227824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            return -1;
227924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
228024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        int handle = addRfcommServiceRecordNative(serviceName,
228124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                uuid.getUuid().getMostSignificantBits(), uuid.getUuid().getLeastSignificantBits(),
228224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                (short)channel);
228324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (DBG) log("new handle " + Integer.toHexString(handle));
228424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (handle == -1) {
228524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            return -1;
228624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
228724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
228824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        int pid = Binder.getCallingPid();
228924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        mServiceRecordToPid.put(new Integer(handle), new Integer(pid));
229024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        try {
229124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            b.linkToDeath(new Reaper(handle, pid), 0);
229224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        } catch (RemoteException e) {}
229324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        return handle;
229424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    }
229524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
229624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    public void removeServiceRecord(int handle) {
229724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
229824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                                                "Need BLUETOOTH permission");
229924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        checkAndRemoveRecord(handle, Binder.getCallingPid());
230024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    }
230124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
230224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private synchronized void checkAndRemoveRecord(int handle, int pid) {
230324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        Integer handleInt = new Integer(handle);
230424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        Integer owner = mServiceRecordToPid.get(handleInt);
230524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (owner != null && pid == owner.intValue()) {
230624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            if (DBG) log("Removing service record " + Integer.toHexString(handle) + " for pid " +
230724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                    pid);
230824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            mServiceRecordToPid.remove(handleInt);
230924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            removeServiceRecordNative(handle);
231024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
231124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    }
231224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
231324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private class Reaper implements IBinder.DeathRecipient {
231424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        int pid;
231524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        int handle;
231624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        Reaper(int handle, int pid) {
231724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            this.pid = pid;
231824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            this.handle = handle;
231924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
232024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        public void binderDied() {
232124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            synchronized (BluetoothService.this) {
232224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                if (DBG) log("Tracked app " + pid + " died");
232324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                checkAndRemoveRecord(handle, pid);
232424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            }
232524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
232624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    }
232724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
23289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
23299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
23309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onReceive(Context context, Intent intent) {
23316e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh            if (intent == null) return;
23326e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh
23339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String action = intent.getAction();
23349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
23359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ContentResolver resolver = context.getContentResolver();
23369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Query the airplane mode from Settings.System just to make sure that
23379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // some random app is not sending this intent and disabling bluetooth
23389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                boolean enabled = !isAirplaneModeOn();
23399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // If bluetooth is currently expected to be on, then enable or disable bluetooth
23409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (Settings.Secure.getInt(resolver, Settings.Secure.BLUETOOTH_ON, 0) > 0) {
23419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (enabled) {
2342105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                        enable(false);
23439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } else {
23449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        disable(false);
23459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
23469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
23476e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh            } else if (Intent.ACTION_DOCK_EVENT.equals(action)) {
23486e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                int state = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
23496e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                        Intent.EXTRA_DOCK_STATE_UNDOCKED);
23506e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                if (DBG) Log.v(TAG, "Received ACTION_DOCK_EVENT with State:" + state);
23516e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                if (state == Intent.EXTRA_DOCK_STATE_UNDOCKED) {
23526e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                    mDockAddress = null;
23536e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                    mDockPin = null;
23546e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                } else {
23556e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                    SharedPreferences.Editor editor =
23566e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                        mContext.getSharedPreferences(SHARED_PREFERENCES_NAME,
23576e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                                mContext.MODE_PRIVATE).edit();
23586e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                    editor.putBoolean(SHARED_PREFERENCE_DOCK_ADDRESS + mDockAddress, true);
235966fce5068a8a3aeb28aaf713843891b286a75280Brad Fitzpatrick                    editor.apply();
23606e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                }
23619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
23629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
23639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
23649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
23656e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh    private void registerForAirplaneMode(IntentFilter filter) {
236644303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        final ContentResolver resolver = mContext.getContentResolver();
236744303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        final String airplaneModeRadios = Settings.System.getString(resolver,
23689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Settings.System.AIRPLANE_MODE_RADIOS);
236944303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        final String toggleableRadios = Settings.System.getString(resolver,
237044303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey                Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
237144303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey
237244303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        mIsAirplaneSensitive = airplaneModeRadios == null ? true :
237344303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey                airplaneModeRadios.contains(Settings.System.RADIO_BLUETOOTH);
237444303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        mIsAirplaneToggleable = toggleableRadios == null ? false :
237544303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey                toggleableRadios.contains(Settings.System.RADIO_BLUETOOTH);
237644303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey
23779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mIsAirplaneSensitive) {
23786e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh            filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
23799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
23809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
23819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
23829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* Returns true if airplane mode is currently on */
23839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final boolean isAirplaneModeOn() {
23849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return Settings.System.getInt(mContext.getContentResolver(),
23859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Settings.System.AIRPLANE_MODE_ON, 0) == 1;
23869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
23879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
23881caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    /* Broadcast the Uuid intent */
23891caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    /*package*/ synchronized void sendUuidIntent(String address) {
23906179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh        ParcelUuid[] uuid = getUuidFromCache(address);
23916179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh        Intent intent = new Intent(BluetoothDevice.ACTION_UUID);
23922d3b98d868cda30535505b2a2fba47aa1c9c052bJaikumar Ganesh        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
23936179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh        intent.putExtra(BluetoothDevice.EXTRA_UUID, uuid);
23946179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh        mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
23951caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
23966179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh        if (mUuidIntentTracker.contains(address))
23971caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            mUuidIntentTracker.remove(address);
239816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
239916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    }
240016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
240116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    /*package*/ synchronized void makeServiceChannelCallbacks(String address) {
240216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        for (Iterator<RemoteService> iter = mUuidCallbackTracker.keySet().iterator();
240316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                iter.hasNext();) {
240416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            RemoteService service = iter.next();
240516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (service.address.equals(address)) {
240616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (DBG) log("Cleaning up failed UUID channel lookup: " + service.address +
240716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        " " + service.uuid);
240816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                IBluetoothCallback callback = mUuidCallbackTracker.get(service);
240916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (callback != null) {
241016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    try {
241116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        callback.onRfcommChannelFound(-1);
241216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    } catch (RemoteException e) {Log.e(TAG, "", e);}
241316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                }
241416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
241516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                iter.remove();
241616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
241716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
24181caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    }
24191caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
24209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
24219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2422105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        switch(mBluetoothState) {
2423de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_OFF:
242424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            pw.println("Bluetooth OFF\n");
2425105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return;
2426de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_TURNING_ON:
242724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            pw.println("Bluetooth TURNING ON\n");
2428105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return;
2429de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_TURNING_OFF:
243024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            pw.println("Bluetooth TURNING OFF\n");
2431105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return;
2432de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_ON:
243324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            pw.println("Bluetooth ON\n");
2434105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
2435105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
243624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("mIsAirplaneSensitive = " + mIsAirplaneSensitive);
243744303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        pw.println("mIsAirplaneToggleable = " + mIsAirplaneToggleable);
243824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
243924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("Local address = " + getAddress());
244024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("Local name = " + getName());
244124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("isDiscovering() = " + isDiscovering());
2442105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
244396a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh        mAdapter.getProfileProxy(mContext,
244496a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh                                 mBluetoothProfileServiceListener, BluetoothProfile.HEADSET);
2445105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
2446105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        pw.println("\n--Known devices--");
2447bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        for (String address : mDeviceProperties.keySet()) {
24481eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly            int bondState = mBondState.getBondState(address);
2449105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            pw.printf("%s %10s (%d) %s\n", address,
24501eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly                       toBondStateString(bondState),
2451105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                       mBondState.getAttempt(address),
2452105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                       getRemoteName(address));
245324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
245424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            Map<ParcelUuid, Integer> uuidChannels = mDeviceServiceChannelCache.get(address);
245524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            if (uuidChannels == null) {
245624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                pw.println("\tuuids = null");
245724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            } else {
245824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                for (ParcelUuid uuid : uuidChannels.keySet()) {
245924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                    Integer channel = uuidChannels.get(uuid);
246024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                    if (channel == null) {
246124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                        pw.println("\t" + uuid);
246224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                    } else {
246324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                        pw.println("\t" + uuid + " RFCOMM channel = " + channel);
24641eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly                    }
24651eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly                }
24661eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly            }
246716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            for (RemoteService service : mUuidCallbackTracker.keySet()) {
246816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (service.address.equals(address)) {
246916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    pw.println("\tPENDING CALLBACK: " + service.uuid);
247016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                }
247116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
2472105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
2473105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
2474d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String value = getProperty("Devices");
24751eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly        String[] devicesObjectPath = null;
2476d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (value != null) {
2477d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            devicesObjectPath = value.split(",");
2478d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
2479105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        pw.println("\n--ACL connected devices--");
248024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (devicesObjectPath != null) {
248124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            for (String device : devicesObjectPath) {
248224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                pw.println(getAddressFromObjectPath(device));
248324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            }
2484105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
2485105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
2486105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Rather not do this from here, but no-where else and I need this
2487105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // dump
2488105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        pw.println("\n--Headset Service--");
248996a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh        if (mBluetoothHeadset != null) {
249096a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh           Set<BluetoothDevice> deviceSet = mBluetoothHeadset.getConnectedDevices();
249196a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh           if (deviceSet.size() == 0) {
249296a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh              pw.println("\n--No headsets connected--");
249396a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh           }
249496a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh           BluetoothDevice device = (BluetoothDevice) deviceSet.toArray()[0];
249596a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh
249696a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh            switch (mBluetoothHeadset.getConnectionState(device)) {
249796a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh                case BluetoothHeadset.STATE_DISCONNECTED:
249896a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh                    pw.println("getConnectionState() = STATE_DISCONNECTED");
249996a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh                    break;
250096a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh                case BluetoothHeadset.STATE_CONNECTING:
250196a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh                    pw.println("getConnectionState() = STATE_CONNECTING");
250296a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh                    break;
250396a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh                case BluetoothHeadset.STATE_CONNECTED:
250496a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh                    pw.println("getConnectionState() = STATE_CONNECTED");
250596a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh                    break;
250696a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh                case BluetoothHeadset.STATE_DISCONNECTING:
250796a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh                    pw.println("getConnectionState() = STATE_DISCONNECTING");
250896a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh                    break;
250996a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh                case BluetoothHeadset.STATE_AUDIO_CONNECTED:
251096a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh                    pw.println("getConnectionState() = STATE_AUDIO_CONNECTED");
251196a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh                    break;
251296a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh            }
251396a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh
251496a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh            deviceSet.clear();
251596a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh            deviceSet = mBluetoothHeadset.getDevicesMatchingConnectionStates(new int[] {
251696a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh                     BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED});
251796a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh            pw.println("\n--Connected and Disconnected Headsets");
251896a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh            for (BluetoothDevice dev: deviceSet) {
251996a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh                pw.println(device);
252096a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh                if (mBluetoothHeadset.isAudioConnected(device)) {
252196a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh                    pw.println("SCO audio connected to device:" + device);
252296a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh                }
252396a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh            }
252496a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh
252596a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh            pw.println("\ngetCurrentHeadset() = " + device);
252696a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh            pw.println("getBatteryUsageHint() = " +
252796a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh                       mBluetoothHeadset.getBatteryUsageHint(device));
252896a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh            mAdapter.closeProfileProxy(BluetoothProfile.HEADSET, mBluetoothHeadset);
2529105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
25306c901db72dbaf57d8fdf26adae6721de14ecae22Nick Pelly
253124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("\n--Application Service Records--");
253224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        for (Integer handle : mServiceRecordToPid.keySet()) {
253324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            Integer pid = mServiceRecordToPid.get(handle);
253424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            pw.println("\tpid " + pid + " handle " + Integer.toHexString(handle));
253524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
25369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
25379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
253896a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh    private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
253996a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh        new BluetoothProfile.ServiceListener() {
254096a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh        public void onServiceConnected(int profile, BluetoothProfile proxy) {
254196a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh            mBluetoothHeadset = (BluetoothHeadset) proxy;
254296a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh    }
254396a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh        public void onServiceDisconnected(int profile) {
254496a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh            mBluetoothHeadset = null;
254596a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh        }
254696a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh    };
254796a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh
2548d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ static int bluezStringToScanMode(boolean pairable, boolean discoverable) {
2549d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (pairable && discoverable)
2550bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            return BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE;
2551d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        else if (pairable && !discoverable)
2552bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            return BluetoothAdapter.SCAN_MODE_CONNECTABLE;
2553d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        else
2554bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            return BluetoothAdapter.SCAN_MODE_NONE;
25559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
25569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
25579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* package */ static String scanModeToBluezString(int mode) {
25589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        switch (mode) {
2559bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        case BluetoothAdapter.SCAN_MODE_NONE:
25609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "off";
2561bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
25629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "connectable";
2563bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
25649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "discoverable";
25659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
25669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return null;
25679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
25689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2569d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /*package*/ String getAddressFromObjectPath(String objectPath) {
2570b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh        String adapterObjectPath = getPropertyInternal("ObjectPath");
2571d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (adapterObjectPath == null || objectPath == null) {
2572f51eadaf1f83abfe16a609a4ded6d789494689b2Jake Hamby            Log.e(TAG, "getAddressFromObjectPath: AdapterObjectPath:" + adapterObjectPath +
2573d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                    "  or deviceObjectPath:" + objectPath + " is null");
2574d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return null;
2575d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
2576d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (!objectPath.startsWith(adapterObjectPath)) {
2577f51eadaf1f83abfe16a609a4ded6d789494689b2Jake Hamby            Log.e(TAG, "getAddressFromObjectPath: AdapterObjectPath:" + adapterObjectPath +
2578d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                    "  is not a prefix of deviceObjectPath:" + objectPath +
2579d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                    "bluetoothd crashed ?");
2580d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return null;
2581d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
2582d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String address = objectPath.substring(adapterObjectPath.length());
2583d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (address != null) return address.replace('_', ':');
2584d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
2585d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        Log.e(TAG, "getAddressFromObjectPath: Address being returned is null");
2586d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return null;
2587d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
2588d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
2589d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /*package*/ String getObjectPathFromAddress(String address) {
2590b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh        String path = getPropertyInternal("ObjectPath");
2591d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (path == null) {
2592d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            Log.e(TAG, "Error: Object Path is null");
2593d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return null;
2594d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
2595d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        path = path + address.replace(":", "_");
2596d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return path;
2597d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
2598d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
2599b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh    /*package */ void setLinkTimeout(String address, int num_slots) {
2600b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh        String path = getObjectPathFromAddress(address);
2601b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh        boolean result = setLinkTimeoutNative(path, num_slots);
2602b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh
2603b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh        if (!result) log("Set Link Timeout to:" + num_slots + " slots failed");
2604b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh    }
2605b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh
26069b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public boolean connectHeadset(String address) {
260796a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh        if (getBondState(address) != BluetoothDevice.BOND_BONDED) return false;
260896a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh
2609f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
26109b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (state != null) {
2611f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            Message msg = new Message();
2612f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.arg1 = BluetoothDeviceProfileState.CONNECT_HFP_OUTGOING;
2613f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.obj = state;
2614f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            mHfpProfileState.sendMessage(msg);
2615f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            return true;
26169b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
26179b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        return false;
26189b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
26199b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
26209b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public boolean disconnectHeadset(String address) {
262196a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh        if (getBondState(address) != BluetoothDevice.BOND_BONDED) return false;
262296a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh
2623f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
26249b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (state != null) {
2625f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            Message msg = new Message();
2626f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.arg1 = BluetoothDeviceProfileState.DISCONNECT_HFP_OUTGOING;
2627f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.obj = state;
2628f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            mHfpProfileState.sendMessage(msg);
26299b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            return true;
26309b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
26319b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        return false;
26329b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
26339b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
26349b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public boolean connectSink(String address) {
263596a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh        if (getBondState(address) != BluetoothDevice.BOND_BONDED) return false;
263696a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh
2637f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
26389b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (state != null) {
2639f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            Message msg = new Message();
2640f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.arg1 = BluetoothDeviceProfileState.CONNECT_A2DP_OUTGOING;
2641f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.obj = state;
2642f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            mA2dpProfileState.sendMessage(msg);
2643f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            return true;
26449b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
26459b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        return false;
26469b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
26479b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
26489b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public boolean disconnectSink(String address) {
264996a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh        if (getBondState(address) != BluetoothDevice.BOND_BONDED) return false;
265096a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh
2651f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
26529b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (state != null) {
2653f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            Message msg = new Message();
2654f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.arg1 = BluetoothDeviceProfileState.DISCONNECT_A2DP_OUTGOING;
2655f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.obj = state;
2656f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            mA2dpProfileState.sendMessage(msg);
26579b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            return true;
26589b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
26599b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        return false;
26609b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
26619b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
2662f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh    private BluetoothDeviceProfileState addProfileState(String address) {
2663f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
26649b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (state != null) return state;
26659b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
2666f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        state = new BluetoothDeviceProfileState(mContext, address, this, mA2dpService);
2667f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        mDeviceProfileState.put(address, state);
26689b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        state.start();
26699b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        return state;
26709b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
26719b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
26729b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    private void removeProfileState(String address) {
2673f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        mDeviceProfileState.remove(address);
26749b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
26759b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
26769b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    private void initProfileState() {
26779b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        String []bonds = null;
26789b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        String val = getPropertyInternal("Devices");
26799b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (val != null) {
26809b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            bonds = val.split(",");
26819b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
26829b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (bonds == null) {
26839b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            return;
26849b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
26859b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
26869b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        for (String path : bonds) {
26879b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            String address = getAddressFromObjectPath(path);
2688f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            BluetoothDeviceProfileState state = addProfileState(address);
26899b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            // Allow 8 secs for SDP records to get registered.
26909b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            Message msg = new Message();
2691f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.what = BluetoothDeviceProfileState.AUTO_CONNECT_PROFILES;
26929b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            state.sendMessageDelayed(msg, 8000);
26939b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
26949b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
26959b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
26969b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public boolean notifyIncomingConnection(String address) {
2697f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        BluetoothDeviceProfileState state =
2698f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh             mDeviceProfileState.get(address);
26999b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (state != null) {
27009b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            Message msg = new Message();
2701f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.what = BluetoothDeviceProfileState.CONNECT_HFP_INCOMING;
27029b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            state.sendMessage(msg);
27039b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            return true;
27049b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
27059b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        return false;
27069b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
27079b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
27089b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    /*package*/ boolean notifyIncomingA2dpConnection(String address) {
2709f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh       BluetoothDeviceProfileState state =
2710f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            mDeviceProfileState.get(address);
27119b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh       if (state != null) {
27129b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh           Message msg = new Message();
2713f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh           msg.what = BluetoothDeviceProfileState.CONNECT_A2DP_INCOMING;
27149b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh           state.sendMessage(msg);
27159b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh           return true;
27169b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh       }
27179b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh       return false;
27189b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
27199b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
27209b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    /*package*/ void setA2dpService(BluetoothA2dpService a2dpService) {
27219b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        mA2dpService = a2dpService;
27229b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
27239b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
272470a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh    public void sendProfileStateMessage(int profile, int cmd) {
272570a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh        Message msg = new Message();
272670a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh        msg.what = cmd;
272770a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh        if (profile == BluetoothProfileState.HFP) {
272870a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh            mHfpProfileState.sendMessage(msg);
272970a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh        } else if (profile == BluetoothProfileState.A2DP) {
273070a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh            mA2dpProfileState.sendMessage(msg);
273170a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh        }
273270a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh    }
273370a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh
27349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static void log(String msg) {
27359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Log.d(TAG, msg);
27369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2737d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
2738d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native static void classInitNative();
2739d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native void initializeNativeDataNative();
2740d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setupNativeDataNative();
2741d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean tearDownNativeDataNative();
2742d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native void cleanupNativeDataNative();
2743d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native String getAdapterPathNative();
2744d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
2745d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native int isEnabledNative();
2746d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native int enableNative();
2747d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native int disableNative();
2748d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
2749d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native Object[] getAdapterPropertiesNative();
2750d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native Object[] getDevicePropertiesNative(String objectPath);
2751d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setAdapterPropertyStringNative(String key, String value);
2752d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setAdapterPropertyIntegerNative(String key, int value);
2753d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setAdapterPropertyBooleanNative(String key, int value);
2754d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
2755d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean startDiscoveryNative();
2756d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean stopDiscoveryNative();
2757d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
2758d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean createPairedDeviceNative(String address, int timeout_ms);
2759cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    private native boolean createPairedDeviceOutOfBandNative(String address, int timeout_ms);
2760cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    private native byte[] readAdapterOutOfBandDataNative();
2761cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
2762d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean cancelDeviceCreationNative(String address);
2763d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean removeDeviceNative(String objectPath);
2764d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native int getDeviceServiceChannelNative(String objectPath, String uuid,
2765d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            int attributeId);
2766d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
2767b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    private native boolean cancelPairingUserInputNative(String address, int nativeData);
2768d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setPinNative(String address, String pin, int nativeData);
2769b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    private native boolean setPasskeyNative(String address, int passkey, int nativeData);
2770b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    private native boolean setPairingConfirmationNative(String address, boolean confirm,
2771b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            int nativeData);
2772cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    private native boolean setRemoteOutOfBandDataNative(String address, byte[] hash,
2773cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh                                                        byte[] randomizer, int nativeData);
2774cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
277524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private native boolean setDevicePropertyBooleanNative(String objectPath, String key,
277624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            int value);
27771caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    private native boolean createDeviceNative(String address);
277816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    /*package*/ native boolean discoverServicesNative(String objectPath, String pattern);
277910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
278024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private native int addRfcommServiceRecordNative(String name, long uuidMsb, long uuidLsb,
278124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            short channel);
278224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private native boolean removeServiceRecordNative(int handle);
2783b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh    private native boolean setLinkTimeoutNative(String path, int num_slots);
2784545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh    private native boolean connectInputDeviceNative(String path);
2785545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh    private native boolean disconnectInputDeviceNative(String path);
27866fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang
27876fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang    private native boolean setBluetoothTetheringNative(boolean value, String nap, String bridge);
27886fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang    private native boolean connectPanDeviceNative(String path, String srcRole, String dstRole);
27896fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang    private native boolean disconnectPanDeviceNative(String path);
27909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
2791