BluetoothService.java revision a224f70b1efc29d9698da5b5c143251a43838f2b
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;
32f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganeshimport android.bluetooth.BluetoothProfileState;
3324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pellyimport android.bluetooth.BluetoothSocket;
3410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganeshimport android.bluetooth.BluetoothUuid;
35bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pellyimport android.bluetooth.IBluetooth;
3616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pellyimport android.bluetooth.IBluetoothCallback;
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.BroadcastReceiver;
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ContentResolver;
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Intent;
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.IntentFilter;
426e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganeshimport android.content.SharedPreferences;
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Binder;
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Handler;
453fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport android.os.IBinder;
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Message;
473fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport android.os.ParcelUuid;
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.RemoteException;
49105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Projectimport android.os.ServiceManager;
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemService;
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.Settings;
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log;
53cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganeshimport android.util.Pair;
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
55d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganeshimport com.android.internal.app.IBatteryStats;
56d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
573fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.BufferedInputStream;
58c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganeshimport java.io.BufferedReader;
593fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.BufferedWriter;
60c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganeshimport java.io.DataInputStream;
61c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganeshimport java.io.File;
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileDescriptor;
633fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.FileInputStream;
643fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.FileNotFoundException;
65c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganeshimport java.io.FileOutputStream;
663fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.FileWriter;
673fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.IOException;
68c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganeshimport java.io.InputStreamReader;
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.PrintWriter;
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.UnsupportedEncodingException;
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList;
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Arrays;
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.HashMap;
7416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pellyimport java.util.Iterator;
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Map;
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
77bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pellypublic class BluetoothService extends IBluetooth.Stub {
78bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    private static final String TAG = "BluetoothService";
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final boolean DBG = true;
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mNativeData;
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private BluetoothEventLoop mEventLoop;
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mIsAirplaneSensitive;
8444303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey    private boolean mIsAirplaneToggleable;
85105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private int mBluetoothState;
86997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly    private boolean mRestart = false;  // need to call enable() after disable()
87bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    private boolean mIsDiscovering;
88997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly
89bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    private BluetoothAdapter mAdapter;  // constant after init()
90997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly    private final BondState mBondState = new BondState();  // local cache of bondings
91105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private final IBatteryStats mBatteryStats;
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final Context mContext;
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
973fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    private static final String DOCK_ADDRESS_PATH = "/sys/class/switch/dock/bt_addr";
983fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    private static final String DOCK_PIN_PATH = "/sys/class/switch/dock/bt_pin";
993fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
1006e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh    private static final String SHARED_PREFERENCE_DOCK_ADDRESS = "dock_bluetooth_address";
1016e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh    private static final String SHARED_PREFERENCES_NAME = "bluetooth_service_settings";
1026e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh
103105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private static final int MESSAGE_REGISTER_SDP_RECORDS = 1;
104105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private static final int MESSAGE_FINISH_DISABLE = 2;
1051caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    private static final int MESSAGE_UUID_INTENT = 3;
10612835478ee687a493d1b5882e67b6725bd539c26Nick Pelly    private static final int MESSAGE_DISCOVERABLE_TIMEOUT = 4;
107a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    private static final int MESSAGE_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 5;
108a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh
109a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    // The time (in millisecs) to delay the pairing attempt after the first
110a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    // auto pairing attempt fails. We use an exponential delay with
111a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    // INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY as the initial value and
112a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    // MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY as the max value.
113a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    private static final long INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 3000;
114a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    private static final long MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 12000;
1151caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
1161caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    // The timeout used to sent the UUIDs Intent
1171caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    // This timeout should be greater than the page timeout
1181caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    private static final int UUID_INTENT_DELAY = 6000;
119105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
12016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    /** Always retrieve RFCOMM channel for these SDP UUIDs */
12116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private static final ParcelUuid[] RFCOMM_UUIDS = {
12216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            BluetoothUuid.Handsfree,
12316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            BluetoothUuid.HSP,
12416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            BluetoothUuid.ObexObjectPush };
12516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
1269b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    // TODO(): Optimize all these string handling
127bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    private final Map<String, String> mAdapterProperties;
12816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private final HashMap<String, Map<String, String>> mDeviceProperties;
129d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
13016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private final HashMap<String, Map<ParcelUuid, Integer>> mDeviceServiceChannelCache;
13116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private final ArrayList<String> mUuidIntentTracker;
13216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private final HashMap<RemoteService, IBluetoothCallback> mUuidCallbackTracker;
1331caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
13424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private final HashMap<Integer, Integer> mServiceRecordToPid;
13524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
136f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh    private final HashMap<String, BluetoothDeviceProfileState> mDeviceProfileState;
137f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh    private final BluetoothProfileState mA2dpProfileState;
138f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh    private final BluetoothProfileState mHfpProfileState;
1399b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
1409b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    private BluetoothA2dpService mA2dpService;
141cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    private final HashMap<String, Pair<byte[], byte[]>> mDeviceOobData;
142cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
1433fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    private static String mDockAddress;
1443fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    private String mDockPin;
1453fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
14616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private static class RemoteService {
14716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        public String address;
14816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        public ParcelUuid uuid;
14916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        public RemoteService(String address, ParcelUuid uuid) {
15016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            this.address = address;
15116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            this.uuid = uuid;
15216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
15316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        @Override
15416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        public boolean equals(Object o) {
15516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (o instanceof RemoteService) {
15616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                RemoteService service = (RemoteService)o;
15716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                return address.equals(service.address) && uuid.equals(service.uuid);
15816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
15916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            return false;
16016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
1615f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root
1625f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root        @Override
1635f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root        public int hashCode() {
1645f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root            int hash = 1;
1655f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root            hash = hash * 31 + (address == null ? 0 : address.hashCode());
1665f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root            hash = hash * 31 + (uuid == null ? 0 : uuid.hashCode());
1675f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root            return hash;
1685f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root        }
16916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    }
17016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static {
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        classInitNative();
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
175bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    public BluetoothService(Context context) {
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext = context;
177105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
178105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Need to do this in place of:
179105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // mBatteryStats = BatteryStatsService.getService();
180105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Since we can not import BatteryStatsService from here. This class really needs to be
181105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // moved to java/services/com/android/server/
182105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo"));
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        initializeNativeDataNative();
185ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project
186ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project        if (isEnabledNative() == 1) {
187ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project            Log.w(TAG, "Bluetooth daemons already running - runtime restart? ");
188ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project            disableNative();
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
190ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project
191de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        mBluetoothState = BluetoothAdapter.STATE_OFF;
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mIsDiscovering = false;
193bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mAdapterProperties = new HashMap<String, String>();
194bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mDeviceProperties = new HashMap<String, Map<String,String>>();
19510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
19610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        mDeviceServiceChannelCache = new HashMap<String, Map<ParcelUuid, Integer>>();
197cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        mDeviceOobData = new HashMap<String, Pair<byte[], byte[]>>();
1981caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        mUuidIntentTracker = new ArrayList<String>();
19916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        mUuidCallbackTracker = new HashMap<RemoteService, IBluetoothCallback>();
20024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        mServiceRecordToPid = new HashMap<Integer, Integer>();
201f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        mDeviceProfileState = new HashMap<String, BluetoothDeviceProfileState>();
202f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        mA2dpProfileState = new BluetoothProfileState(mContext, BluetoothProfileState.A2DP);
203f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        mHfpProfileState = new BluetoothProfileState(mContext, BluetoothProfileState.HFP);
204f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh
205f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        mHfpProfileState.start();
206f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        mA2dpProfileState.start();
2073fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
2083fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        IntentFilter filter = new IntentFilter();
2096e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh        registerForAirplaneMode(filter);
2106e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh
2113fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        filter.addAction(Intent.ACTION_DOCK_EVENT);
2126e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh        mContext.registerReceiver(mReceiver, filter);
2133fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    }
2143fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
2159b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public static synchronized String readDockBluetoothAddress() {
2163fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        if (mDockAddress != null) return mDockAddress;
2173fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
2183fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        BufferedInputStream file = null;
2193fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        String dockAddress;
2203fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        try {
2213fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            file = new BufferedInputStream(new FileInputStream(DOCK_ADDRESS_PATH));
2223fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            byte[] address = new byte[17];
2233fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            file.read(address);
2243fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            dockAddress = new String(address);
2253fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            dockAddress = dockAddress.toUpperCase();
2263fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            if (BluetoothAdapter.checkBluetoothAddress(dockAddress)) {
2273fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                mDockAddress = dockAddress;
2283fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                return mDockAddress;
2293fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            } else {
2303fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                log("CheckBluetoothAddress failed for car dock address:" + dockAddress);
2313fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            }
2323fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        } catch (FileNotFoundException e) {
2333fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            log("FileNotFoundException while trying to read dock address");
2343fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        } catch (IOException e) {
2353fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            log("IOException while trying to read dock address");
2363fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        } finally {
2373fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            if (file != null) {
2383fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                try {
2393fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                    file.close();
2403fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                } catch (IOException e) {
2413fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                    // Ignore
2423fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                }
2433fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            }
2443fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        }
2453fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        mDockAddress = null;
2463fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        return null;
2473fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    }
2483fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
2493fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    private synchronized boolean writeDockPin() {
2503fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        BufferedWriter out = null;
2513fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        try {
2523fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            out = new BufferedWriter(new FileWriter(DOCK_PIN_PATH));
2533fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
2543fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            // Generate a random 4 digit pin between 0000 and 9999
2553fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            // This is not truly random but good enough for our purposes.
2563fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            int pin = (int) Math.floor(Math.random() * 10000);
2573fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
2583fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            mDockPin = String.format("%04d", pin);
2593fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            out.write(mDockPin);
2603fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            return true;
2613fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        } catch (FileNotFoundException e) {
2623fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            log("FileNotFoundException while trying to write dock pairing pin");
2633fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        } catch (IOException e) {
2643fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            log("IOException while while trying to write dock pairing pin");
2653fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        } finally {
2663fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            if (out != null) {
2673fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                try {
2683fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                    out.close();
2693fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                } catch (IOException e) {
2703fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                    // Ignore
2713fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                }
2723fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            }
2733fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        }
2743fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        mDockPin = null;
2753fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        return false;
2763fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    }
2773fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
2783fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    /*package*/ synchronized String getDockPin() {
2793fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        return mDockPin;
280bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    }
281bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly
282bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    public synchronized void initAfterRegistration() {
283f242b7b931898856bcbcb7ec36cacf43098ba544Nick Pelly        mAdapter = BluetoothAdapter.getDefaultAdapter();
284bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mEventLoop = new BluetoothEventLoop(mContext, mAdapter, this);
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void finalize() throws Throwable {
2896e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh        mContext.unregisterReceiver(mReceiver);
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            cleanupNativeDataNative();
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super.finalize();
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean isEnabled() {
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
2998c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        return isEnabledInternal();
3008c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh    }
3018c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
3028c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh    private boolean isEnabledInternal() {
303de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        return mBluetoothState == BluetoothAdapter.STATE_ON;
3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
306105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    public int getBluetoothState() {
307105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
308105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        return mBluetoothState;
309105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    }
310105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
311105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Bring down bluetooth and disable BT in settings. Returns true on success.
3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean disable() {
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return disable(true);
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Bring down bluetooth. Returns true on success.
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
322e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly     * @param saveSetting If true, persist the new setting
3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean disable(boolean saveSetting) {
325e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission");
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
327105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        switch (mBluetoothState) {
328de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_OFF:
329105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return true;
330de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_ON:
331105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            break;
332105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        default:
333105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return false;
334105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mEnableThread != null && mEnableThread.isAlive()) {
3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
338de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        setBluetoothState(BluetoothAdapter.STATE_TURNING_OFF);
339bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly        mHandler.removeMessages(MESSAGE_REGISTER_SDP_RECORDS);
340105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
341105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Allow 3 seconds for profiles to gracefully disconnect
342105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // TODO: Introduce a callback mechanism so that each profile can notify
343bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        // BluetoothService when it is done shutting down
344105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mHandler.sendMessageDelayed(
345105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                mHandler.obtainMessage(MESSAGE_FINISH_DISABLE, saveSetting ? 1 : 0, 0), 3000);
346105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        return true;
347105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    }
348105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
349105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
350105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private synchronized void finishDisable(boolean saveSetting) {
351de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        if (mBluetoothState != BluetoothAdapter.STATE_TURNING_OFF) {
352105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return;
3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mEventLoop.stop();
355d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        tearDownNativeDataNative();
3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        disableNative();
3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // mark in progress bondings as cancelled
3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (String address : mBondState.listInState(BluetoothDevice.BOND_BONDING)) {
360005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            mBondState.setBondState(address, BluetoothDevice.BOND_NONE,
3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // update mode
365de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        Intent intent = new Intent(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
366de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        intent.putExtra(BluetoothAdapter.EXTRA_SCAN_MODE, BluetoothAdapter.SCAN_MODE_NONE);
3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.sendBroadcast(intent, BLUETOOTH_PERM);
3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
369105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mIsDiscovering = false;
370bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mAdapterProperties.clear();
37124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        mServiceRecordToPid.clear();
372105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (saveSetting) {
3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            persistBluetoothOnSetting(false);
3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
376105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
377de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        setBluetoothState(BluetoothAdapter.STATE_OFF);
378105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
379105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Log bluetooth off to battery stats.
380105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        long ident = Binder.clearCallingIdentity();
381105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        try {
382105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            mBatteryStats.noteBluetoothOff();
383105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        } catch (RemoteException e) {
384105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        } finally {
385105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            Binder.restoreCallingIdentity(ident);
386105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
387997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly
388997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        if (mRestart) {
389997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly            mRestart = false;
390997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly            enable();
391997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        }
3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
394105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    /** Bring up BT and persist BT on in settings */
395105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    public boolean enable() {
396105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        return enable(true);
3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Enable this Bluetooth device, asynchronously.
4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * This turns on/off the underlying hardware.
4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
403105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project     * @param saveSetting If true, persist the new state of BT in settings
404105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project     * @return True on success (so far)
4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
406105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    public synchronized boolean enable(boolean saveSetting) {
4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Airplane mode can prevent Bluetooth radio from being turned on.
41144303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        if (mIsAirplaneSensitive && isAirplaneModeOn() && !mIsAirplaneToggleable) {
4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
414de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        if (mBluetoothState != BluetoothAdapter.STATE_OFF) {
4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mEnableThread != null && mEnableThread.isAlive()) {
4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
420de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        setBluetoothState(BluetoothAdapter.STATE_TURNING_ON);
421105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mEnableThread = new EnableThread(saveSetting);
4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mEnableThread.start();
4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
426997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly    /** Forcibly restart Bluetooth if it is on */
427997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly    /* package */ synchronized void restart() {
428de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        if (mBluetoothState != BluetoothAdapter.STATE_ON) {
429997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly            return;
430997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        }
431997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        mRestart = true;
432997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        if (!disable(false)) {
433997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly            mRestart = false;
434997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        }
435d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
436997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly
437105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private synchronized void setBluetoothState(int state) {
438105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        if (state == mBluetoothState) {
439105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return;
440105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
441105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
442105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        if (DBG) log("Bluetooth state " + mBluetoothState + " -> " + state);
443105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
444de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
445de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, mBluetoothState);
446de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        intent.putExtra(BluetoothAdapter.EXTRA_STATE, state);
447105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
448105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
449105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mBluetoothState = state;
450105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
451105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mContext.sendBroadcast(intent, BLUETOOTH_PERM);
452105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    }
453105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final Handler mHandler = new Handler() {
4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void handleMessage(Message msg) {
4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            switch (msg.what) {
458105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            case MESSAGE_REGISTER_SDP_RECORDS:
4598c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh                if (!isEnabledInternal()) {
460bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    return;
461bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                }
462bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                // SystemService.start() forks sdptool to register service
463bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                // records. It can fail to register some records if it is
464bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                // forked multiple times in a row, probably because there is
465bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                // some race in sdptool or bluez when operated in parallel.
466bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                // As a workaround, delay 500ms between each fork of sdptool.
467bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                // TODO: Don't fork sdptool in order to regsiter service
468bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                // records, use a DBUS call instead.
469bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                switch (msg.arg1) {
470bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                case 1:
47177b4ad0e496941a28382eb938a05831f1f8d2d4aJaikumar Ganesh                    Log.d(TAG, "Registering hfag record");
47277b4ad0e496941a28382eb938a05831f1f8d2d4aJaikumar Ganesh                    SystemService.start("hfag");
473bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    mHandler.sendMessageDelayed(
474bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                            mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS, 2, -1), 500);
475bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    break;
476bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                case 2:
47777b4ad0e496941a28382eb938a05831f1f8d2d4aJaikumar Ganesh                    Log.d(TAG, "Registering hsag record");
47877b4ad0e496941a28382eb938a05831f1f8d2d4aJaikumar Ganesh                    SystemService.start("hsag");
479bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    mHandler.sendMessageDelayed(
480bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                            mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS, 3, -1), 500);
481bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    break;
482bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                case 3:
483bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    Log.d(TAG, "Registering opush record");
48403c707ab6fc97e99b1603b8d6edc604dbea3cd6fNick Pelly                    SystemService.start("opush");
485bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    mHandler.sendMessageDelayed(
486bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                            mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS, 4, -1), 500);
487bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    break;
488bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                case 4:
489bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    Log.d(TAG, "Registering pbap record");
49067542964876aa7e4216e8f69f21dda68e7463b9aJaikumar Ganesh                    SystemService.start("pbap");
491bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    break;
4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
493105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                break;
494105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            case MESSAGE_FINISH_DISABLE:
495105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                finishDisable(msg.arg1 != 0);
496105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                break;
4971caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            case MESSAGE_UUID_INTENT:
4981caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh                String address = (String)msg.obj;
49916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (address != null) {
5001caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh                    sendUuidIntent(address);
50116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    makeServiceChannelCallbacks(address);
50216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                }
5031caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh                break;
50412835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            case MESSAGE_DISCOVERABLE_TIMEOUT:
50512835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                int mode = msg.arg1;
5068c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh                if (isEnabledInternal()) {
50712835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                    // TODO: Switch back to the previous scan mode
50812835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                    // This is ok for now, because we only use
50912835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                    // CONNECTABLE and CONNECTABLE_DISCOVERABLE
51012835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                    setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE, -1);
51112835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                }
51212835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                break;
513a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            case MESSAGE_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY:
514a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                address = (String)msg.obj;
515a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                if (address != null) {
516a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                    createBond(address);
517a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                    return;
518a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                }
519a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                break;
5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private EnableThread mEnableThread;
5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private class EnableThread extends Thread {
5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final boolean mSaveSetting;
528105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        public EnableThread(boolean saveSetting) {
5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mSaveSetting = saveSetting;
5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void run() {
5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean res = (enableNative() == 0);
5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (res) {
534b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                int retryCount = 2;
535b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                boolean running = false;
536b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                while ((retryCount-- > 0) && !running) {
537b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    mEventLoop.start();
538105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    // it may take a momement for the other thread to do its
539b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    // thing.  Check periodically for a while.
540b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    int pollCount = 5;
541b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    while ((pollCount-- > 0) && !running) {
542b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                        if (mEventLoop.isEventLoopRunning()) {
543b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                            running = true;
544b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                            break;
545b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                        }
546b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                        try {
547b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                            Thread.sleep(100);
548b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                        } catch (InterruptedException e) {}
549b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    }
550b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                }
551b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                if (!running) {
552b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    log("bt EnableThread giving up");
553b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    res = false;
554b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    disableNative();
555b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                }
5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (res) {
560d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                if (!setupNativeDataNative()) {
561d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                    return;
562d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                }
5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mSaveSetting) {
5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    persistBluetoothOnSetting(true);
5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mIsDiscovering = false;
567c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                mBondState.readAutoPairingData();
5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mBondState.loadBondState();
5699b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                initProfileState();
570bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                mHandler.sendMessageDelayed(
571bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                        mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS, 1, -1), 3000);
5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
573105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                // Log bluetooth on to battery stats.
574105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                long ident = Binder.clearCallingIdentity();
575105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                try {
576105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    mBatteryStats.noteBluetoothOn();
577105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                } catch (RemoteException e) {
578105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                } finally {
579105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    Binder.restoreCallingIdentity(ident);
580105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                }
5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
582105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
583105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            mEnableThread = null;
584105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
585105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            setBluetoothState(res ?
586de893f550301a60274e87aa8168225e7a7a42184Nick Pelly                              BluetoothAdapter.STATE_ON :
587de893f550301a60274e87aa8168225e7a7a42184Nick Pelly                              BluetoothAdapter.STATE_OFF);
588105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
589b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            if (res) {
590105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                // Update mode
591d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                String[] propVal = {"Pairable", getProperty("Pairable")};
592d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                mEventLoop.onPropertyChanged(propVal);
593b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            }
594b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project
59544303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey            if (mIsAirplaneSensitive && isAirplaneModeOn() && !mIsAirplaneToggleable) {
5965c43f735d94a538dc273c8f859d1100a7cdd5c71Daisuke Miyakawa                disable(false);
5975c43f735d94a538dc273c8f859d1100a7cdd5c71Daisuke Miyakawa            }
5985c43f735d94a538dc273c8f859d1100a7cdd5c71Daisuke Miyakawa
5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void persistBluetoothOnSetting(boolean bluetoothOn) {
6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long origCallerIdentityToken = Binder.clearCallingIdentity();
6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.BLUETOOTH_ON,
6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                bluetoothOn ? 1 : 0);
6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Binder.restoreCallingIdentity(origCallerIdentityToken);
6079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
609a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    /*package*/ synchronized boolean attemptAutoPair(String address) {
610a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        if (!mBondState.hasAutoPairingFailed(address) &&
611a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                !mBondState.isAutoPairingBlacklisted(address)) {
612a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            mBondState.attempt(address);
613a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            setPin(address, BluetoothDevice.convertPinToBytes("0000"));
614a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            return true;
615a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        }
616a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        return false;
617a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    }
618a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh
619a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    /*package*/ synchronized void onCreatePairedDeviceResult(String address, int result) {
620a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        if (result == BluetoothDevice.BOND_SUCCESS) {
621a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            setBondState(address, BluetoothDevice.BOND_BONDED);
622a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            if (mBondState.isAutoPairingAttemptsInProgress(address)) {
623a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                mBondState.clearPinAttempts(address);
624a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            }
625a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        } else if (result == BluetoothDevice.UNBOND_REASON_AUTH_FAILED &&
626a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                mBondState.getAttempt(address) == 1) {
627a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            mBondState.addAutoPairingFailure(address);
628a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            pairingAttempt(address, result);
629a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        } else if (result == BluetoothDevice.UNBOND_REASON_REMOTE_DEVICE_DOWN &&
630a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh              mBondState.isAutoPairingAttemptsInProgress(address)) {
631a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            pairingAttempt(address, result);
632a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        } else {
633a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            setBondState(address, BluetoothDevice.BOND_NONE, result);
634a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            if (mBondState.isAutoPairingAttemptsInProgress(address)) {
635a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                mBondState.clearPinAttempts(address);
636a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            }
637a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        }
638a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    }
639a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh
640a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    /*package*/ synchronized String getPendingOutgoingBonding() {
641a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        return mBondState.getPendingOutgoingBonding();
642a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    }
643a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh
644a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    private void pairingAttempt(String address, int result) {
645a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        // This happens when our initial guess of "0000" as the pass key
646a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        // fails. Try to create the bond again and display the pin dialog
647a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        // to the user. Use back-off while posting the delayed
648a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        // message. The initial value is
649a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        // INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY and the max value is
650a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        // MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY. If the max value is
651a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        // reached, display an error to the user.
652a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        int attempt = mBondState.getAttempt(address);
653a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        if (attempt * INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY >
654a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                    MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY) {
655a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            mBondState.clearPinAttempts(address);
656a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            setBondState(address, BluetoothDevice.BOND_NONE, result);
657a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            return;
658a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        }
659a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh
660a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        Message message = mHandler.obtainMessage(MESSAGE_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY);
661a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        message.obj = address;
662a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        boolean postResult =  mHandler.sendMessageDelayed(message,
663a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                                        attempt * INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY);
664a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        if (!postResult) {
665a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            mBondState.clearPinAttempts(address);
666a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            setBondState(address,
667a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                    BluetoothDevice.BOND_NONE, result);
668a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            return;
669a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        }
670a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        mBondState.attempt(address);
6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** local cache of bonding state.
6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* we keep our own state to track the intermediate state BONDING, which
6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* bluez does not track.
6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * All addreses must be passed in upper case.
6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public class BondState {
6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final HashMap<String, Integer> mState = new HashMap<String, Integer>();
6809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final HashMap<String, Integer> mPinAttempt = new HashMap<String, Integer>();
681c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh
682c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        private static final String AUTO_PAIRING_BLACKLIST =
683c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            "/etc/bluetooth/auto_pairing.conf";
684c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        private static final String DYNAMIC_AUTO_PAIRING_BLACKLIST =
685c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            "/data/misc/bluetooth/dynamic_auto_pairing.conf";
686c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        private ArrayList<String>  mAutoPairingAddressBlacklist;
687c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        private ArrayList<String> mAutoPairingExactNameBlacklist;
688c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        private ArrayList<String> mAutoPairingPartialNameBlacklist;
689c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        // Addresses added to blacklist dynamically based on usage.
690c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        private ArrayList<String> mAutoPairingDynamicAddressBlacklist;
691c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh
692482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh
6932092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        // If this is an outgoing connection, store the address.
6942092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        // There can be only 1 pending outgoing connection at a time,
6952092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        private String mPendingOutgoingBonding;
6962092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
6972092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        private synchronized void setPendingOutgoingBonding(String address) {
6982092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh            mPendingOutgoingBonding = address;
6992092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        }
7002092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
7012092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        public synchronized String getPendingOutgoingBonding() {
7022092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh            return mPendingOutgoingBonding;
7032092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        }
7042092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
7059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized void loadBondState() {
706de893f550301a60274e87aa8168225e7a7a42184Nick Pelly            if (mBluetoothState != BluetoothAdapter.STATE_TURNING_ON) {
7079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
7089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
709d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            String []bonds = null;
710b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh            String val = getPropertyInternal("Devices");
711d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            if (val != null) {
712d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                bonds = val.split(",");
713d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            }
7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (bonds == null) {
7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mState.clear();
7189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (DBG) log("found " + bonds.length + " bonded devices");
719d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            for (String device : bonds) {
720d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                mState.put(getAddressFromObjectPath(device).toUpperCase(),
721d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                        BluetoothDevice.BOND_BONDED);
7229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized void setBondState(String address, int state) {
7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setBondState(address, state, 0);
7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /** reason is ignored unless state == BOND_NOT_BONDED */
7309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized void setBondState(String address, int state, int reason) {
7319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int oldState = getBondState(address);
7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (oldState == state) {
7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7352092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
7362092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh            // Check if this was an pending outgoing bonding.
7372092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh            // If yes, reset the state.
7382092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh            if (oldState == BluetoothDevice.BOND_BONDING) {
7392092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh                if (address.equals(mPendingOutgoingBonding)) {
7402092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh                    mPendingOutgoingBonding = null;
7412092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh                }
7422092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh            }
7432092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
7449b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            if (state == BluetoothDevice.BOND_BONDED) {
7459b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                addProfileState(address);
7469b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            } else if (state == BluetoothDevice.BOND_NONE) {
7479b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                removeProfileState(address);
7489b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            }
7499b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
7509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (DBG) log(address + " bond state " + oldState + " -> " + state + " (" +
7519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                         reason + ")");
752005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            Intent intent = new Intent(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
753005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
754005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            intent.putExtra(BluetoothDevice.EXTRA_BOND_STATE, state);
755005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            intent.putExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, oldState);
756005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            if (state == BluetoothDevice.BOND_NONE) {
7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (reason <= 0) {
7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Log.w(TAG, "setBondState() called to unbond device, but reason code is " +
7599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                          "invalid. Overriding reason code with BOND_RESULT_REMOVED");
7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    reason = BluetoothDevice.UNBOND_REASON_REMOVED;
7619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
762005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly                intent.putExtra(BluetoothDevice.EXTRA_REASON, reason);
7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mState.remove(address);
7649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
7659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mState.put(address, state);
7669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mContext.sendBroadcast(intent, BLUETOOTH_PERM);
7699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public boolean isAutoPairingBlacklisted(String address) {
772c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            if (mAutoPairingAddressBlacklist != null) {
773c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                for (String blacklistAddress : mAutoPairingAddressBlacklist) {
774c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    if (address.startsWith(blacklistAddress)) return true;
775c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                }
7769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
777482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh
778c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            if (mAutoPairingDynamicAddressBlacklist != null) {
779c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                for (String blacklistAddress: mAutoPairingDynamicAddressBlacklist) {
780c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    if (address.equals(blacklistAddress)) return true;
781c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                }
782c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            }
783482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh            String name = getRemoteName(address);
784482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh            if (name != null) {
785c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                if (mAutoPairingExactNameBlacklist != null) {
786c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    for (String blacklistName : mAutoPairingExactNameBlacklist) {
787c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        if (name.equals(blacklistName)) return true;
788c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    }
789738ed80262aa26128924c51f59ffd49e1163eb8dJaikumar Ganesh                }
790738ed80262aa26128924c51f59ffd49e1163eb8dJaikumar Ganesh
791c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                if (mAutoPairingPartialNameBlacklist != null) {
792c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    for (String blacklistName : mAutoPairingPartialNameBlacklist) {
793c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        if (name.startsWith(blacklistName)) return true;
794c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    }
795482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh                }
796482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh            }
7979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
7989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized int getBondState(String address) {
8019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Integer state = mState.get(address);
8029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (state == null) {
803005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly                return BluetoothDevice.BOND_NONE;
8049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return state.intValue();
8069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
808e5d93b7ed983f98855555d560faf060836f1a52fJaikumar Ganesh        /*package*/ synchronized String[] listInState(int state) {
8099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ArrayList<String> result = new ArrayList<String>(mState.size());
8109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (Map.Entry<String, Integer> e : mState.entrySet()) {
8119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (e.getValue().intValue() == state) {
8129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    result.add(e.getKey());
8139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
8149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return result.toArray(new String[result.size()]);
8169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized void addAutoPairingFailure(String address) {
819c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            if (mAutoPairingDynamicAddressBlacklist == null) {
820c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                mAutoPairingDynamicAddressBlacklist = new ArrayList<String>();
8219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
822c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh
823c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            updateAutoPairingData(address);
824c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            mAutoPairingDynamicAddressBlacklist.add(address);
8259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized boolean isAutoPairingAttemptsInProgress(String address) {
8289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return getAttempt(address) != 0;
8299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized void clearPinAttempts(String address) {
8329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mPinAttempt.remove(address);
8339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized boolean hasAutoPairingFailed(String address) {
836c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            if (mAutoPairingDynamicAddressBlacklist == null) return false;
837c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh
838c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            return mAutoPairingDynamicAddressBlacklist.contains(address);
8399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized int getAttempt(String address) {
8429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Integer attempt = mPinAttempt.get(address);
8439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (attempt == null) {
8449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return 0;
8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return attempt.intValue();
8479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized void attempt(String address) {
8509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Integer attempt = mPinAttempt.get(address);
8519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int newAttempt;
8529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (attempt == null) {
8539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                newAttempt = 1;
8549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
8559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                newAttempt = attempt.intValue() + 1;
8569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mPinAttempt.put(address, new Integer(newAttempt));
8589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
860c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        private void copyAutoPairingData() {
861c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            File file = null;
862c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            FileInputStream in = null;
863c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            FileOutputStream out = null;
864c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            try {
865c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                file = new File(DYNAMIC_AUTO_PAIRING_BLACKLIST);
866c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                if (file.exists()) return;
867c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh
868c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                in = new FileInputStream(AUTO_PAIRING_BLACKLIST);
869c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                out= new FileOutputStream(DYNAMIC_AUTO_PAIRING_BLACKLIST);
870c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh
871c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                byte[] buf = new byte[1024];
872c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                int len;
873c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                while ((len = in.read(buf)) > 0) {
874c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    out.write(buf, 0, len);
875c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                }
876c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            } catch (FileNotFoundException e) {
877c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                log("FileNotFoundException: in copyAutoPairingData");
878c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            } catch (IOException e) {
879c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                log("IOException: in copyAutoPairingData");
880c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            } finally {
881c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                 try {
882c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                     if (in != null) in.close();
883c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                     if (out != null) out.close();
884c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                 } catch (IOException e) {}
885c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            }
886c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        }
887c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh
888c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        public void readAutoPairingData() {
889c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            if (mAutoPairingAddressBlacklist != null) return;
890c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            copyAutoPairingData();
891c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            FileInputStream fstream = null;
892c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            try {
893c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                fstream = new FileInputStream(DYNAMIC_AUTO_PAIRING_BLACKLIST);
894c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                DataInputStream in = new DataInputStream(fstream);
895c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                BufferedReader file = new BufferedReader(new InputStreamReader(in));
896c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                String line;
897c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                while((line = file.readLine()) != null) {
898c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    line = line.trim();
899c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    if (line.length() == 0 || line.startsWith("//")) continue;
900c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    String[] value = line.split("=");
901c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    if (value != null && value.length == 2) {
902c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        String[] val = value[1].split(",");
903c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        if (value[0].equalsIgnoreCase("AddressBlacklist")) {
904c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                            mAutoPairingAddressBlacklist =
905c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                                new ArrayList<String>(Arrays.asList(val));
906c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        } else if (value[0].equalsIgnoreCase("ExactNameBlacklist")) {
907c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                            mAutoPairingExactNameBlacklist =
908c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                                new ArrayList<String>(Arrays.asList(val));
909c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        } else if (value[0].equalsIgnoreCase("PartialNameBlacklist")) {
910c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                            mAutoPairingPartialNameBlacklist =
911c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                                new ArrayList<String>(Arrays.asList(val));
912c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        } else if (value[0].equalsIgnoreCase("DynamicAddressBlacklist")) {
913c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                            mAutoPairingDynamicAddressBlacklist =
914c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                                new ArrayList<String>(Arrays.asList(val));
915c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        } else {
916c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                            Log.e(TAG, "Error parsing Auto pairing blacklist file");
917c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        }
918c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    }
919c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                }
920c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            } catch (FileNotFoundException e) {
921c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                log("FileNotFoundException: readAutoPairingData" + e.toString());
922c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            } catch (IOException e) {
923c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                log("IOException: readAutoPairingData" + e.toString());
924c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            } finally {
925c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                if (fstream != null) {
926c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    try {
927c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        fstream.close();
928c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    } catch (IOException e) {
929c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        // Ignore
930c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    }
931c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                }
932c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            }
933c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        }
934c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh
935c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        // This function adds a bluetooth address to the auto pairing blacklis
936c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        // file. These addresses are added to DynamicAddressBlacklistSection
937c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        private void updateAutoPairingData(String address) {
938c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            BufferedWriter out = null;
939c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            try {
940c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                out = new BufferedWriter(new FileWriter(DYNAMIC_AUTO_PAIRING_BLACKLIST, true));
941c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                StringBuilder str = new StringBuilder();
942c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                if (mAutoPairingDynamicAddressBlacklist.size() == 0) {
943c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    str.append("DynamicAddressBlacklist=");
944c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                }
945c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                str.append(address);
946c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                str.append(",");
947c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                out.write(str.toString());
948c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            } catch (FileNotFoundException e) {
949c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                log("FileNotFoundException: updateAutoPairingData" + e.toString());
950c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            } catch (IOException e) {
951c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                log("IOException: updateAutoPairingData" + e.toString());
952c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            } finally {
953c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                if (out != null) {
954c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    try {
955c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        out.close();
956c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    } catch (IOException e) {
957c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        // Ignore
958c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    }
959c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                }
960c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            }
961c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        }
9629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static String toBondStateString(int bondState) {
9659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        switch (bondState) {
966005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        case BluetoothDevice.BOND_NONE:
9679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "not bonded";
9689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case BluetoothDevice.BOND_BONDING:
9699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "bonding";
9709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case BluetoothDevice.BOND_BONDED:
9719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "bonded";
9729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        default:
9739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "??????";
9749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9779519ce75f15ba287a641166c1b7ed10f2aa73f74Jaikumar Ganesh    /*package*/ synchronized boolean isAdapterPropertiesEmpty() {
9789519ce75f15ba287a641166c1b7ed10f2aa73f74Jaikumar Ganesh        return mAdapterProperties.isEmpty();
9799519ce75f15ba287a641166c1b7ed10f2aa73f74Jaikumar Ganesh    }
9809519ce75f15ba287a641166c1b7ed10f2aa73f74Jaikumar Ganesh
981d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /*package*/synchronized void getAllProperties() {
9828c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
9839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
984bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mAdapterProperties.clear();
985d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
986d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String properties[] = (String [])getAdapterPropertiesNative();
987d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        // The String Array consists of key-value pairs.
988d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (properties == null) {
989d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            Log.e(TAG, "*Error*: GetAdapterProperties returned NULL");
990d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return;
991d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
992d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
9938bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh        for (int i = 0; i < properties.length; i++) {
9948bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            String name = properties[i];
995efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh            String newValue = null;
9968bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            int len;
9978bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            if (name == null) {
9988bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                Log.e(TAG, "Error:Adapter Property at index" + i + "is null");
9998bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                continue;
10008bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            }
10017a9de8b425954e4039053038e4ec1762b866c83cDanica Chang            if (name.equals("Devices") || name.equals("UUIDs")) {
1002efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                StringBuilder str = new StringBuilder();
10038bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                len = Integer.valueOf(properties[++i]);
10048bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                for (int j = 0; j < len; j++) {
1005efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                    str.append(properties[++i]);
1006efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                    str.append(",");
1007efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                }
1008efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                if (len > 0) {
1009efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                    newValue = str.toString();
10108bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                }
10118bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            } else {
10128bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                newValue = properties[++i];
10138bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            }
1014bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            mAdapterProperties.put(name, newValue);
1015d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
1016d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1017d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        // Add adapter object path property.
1018d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String adapterPath = getAdapterPathNative();
1019d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (adapterPath != null)
1020bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            mAdapterProperties.put("ObjectPath", adapterPath + "/dev_");
10219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1023d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ synchronized void setProperty(String name, String value) {
1024bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mAdapterProperties.put(name, value);
10259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean setName(String name) {
10289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
10299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
10309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (name == null) {
10319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
10329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1033d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setPropertyString("Name", name);
10349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1036d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    //TODO(): setPropertyString, setPropertyInteger, setPropertyBoolean
1037d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    // Either have a single property function with Object as the parameter
1038d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    // or have a function for each property and then obfuscate in the JNI layer.
1039d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    // The following looks dirty.
1040d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private boolean setPropertyString(String key, String value) {
10419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
10428c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
1043d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setAdapterPropertyStringNative(key, value);
10449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1046d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private boolean setPropertyInteger(String key, int value) {
1047d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
10488c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
1049d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setAdapterPropertyIntegerNative(key, value);
1050d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
10519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1052d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private boolean setPropertyBoolean(String key, boolean value) {
1053d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
10548c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
1055d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setAdapterPropertyBooleanNative(key, value ? 1 : 0);
10569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1058d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /**
1059d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Set the discoverability window for the device.  A timeout of zero
1060d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * makes the device permanently discoverable (if the device is
1061d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * discoverable).  Setting the timeout to a nonzero value does not make
1062d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * a device discoverable; you need to call setMode() to make the device
1063d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * explicitly discoverable.
1064d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     *
1065d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * @param timeout_s The discoverable timeout in seconds.
1066d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     */
1067d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized boolean setDiscoverableTimeout(int timeout) {
10689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
10699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
1070d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setPropertyInteger("DiscoverableTimeout", timeout);
10719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
107312835478ee687a493d1b5882e67b6725bd539c26Nick Pelly    public synchronized boolean setScanMode(int mode, int duration) {
107418b1e79a123b979d25bfa5d0b0ee5d0382dbd64bNick Pelly        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS,
107518b1e79a123b979d25bfa5d0b0ee5d0382dbd64bNick Pelly                                                "Need WRITE_SECURE_SETTINGS permission");
1076de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        boolean pairable = false;
1077de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        boolean discoverable = false;
107812835478ee687a493d1b5882e67b6725bd539c26Nick Pelly
1079de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        switch (mode) {
1080de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.SCAN_MODE_NONE:
108112835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            mHandler.removeMessages(MESSAGE_DISCOVERABLE_TIMEOUT);
1082d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            pairable = false;
1083d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            discoverable = false;
1084de893f550301a60274e87aa8168225e7a7a42184Nick Pelly            break;
1085de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
108612835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            mHandler.removeMessages(MESSAGE_DISCOVERABLE_TIMEOUT);
1087d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            pairable = true;
1088d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            discoverable = false;
1089005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            break;
1090de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
109112835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            mHandler.removeMessages(MESSAGE_DISCOVERABLE_TIMEOUT);
1092d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            pairable = true;
1093d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            discoverable = true;
109412835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            Message msg = mHandler.obtainMessage(MESSAGE_DISCOVERABLE_TIMEOUT);
109512835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            mHandler.sendMessageDelayed(msg, duration * 1000);
109612835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            if (DBG) Log.d(TAG, "BT Discoverable for " + duration + " seconds");
1097005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            break;
1098de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        default:
1099de893f550301a60274e87aa8168225e7a7a42184Nick Pelly            Log.w(TAG, "Requested invalid scan mode " + mode);
1100de893f550301a60274e87aa8168225e7a7a42184Nick Pelly            return false;
1101d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
1102d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        setPropertyBoolean("Pairable", pairable);
1103d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        setPropertyBoolean("Discoverable", discoverable);
11049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1105d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return true;
11069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1108b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh    /*package*/ synchronized String getProperty(String name) {
1109b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh        if (!isEnabledInternal()) return null;
1110b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh        return getPropertyInternal(name);
1111b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh    }
1112b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh
1113b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh    /*package*/ synchronized String getPropertyInternal(String name) {
1114bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        if (!mAdapterProperties.isEmpty())
1115bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            return mAdapterProperties.get(name);
1116d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        getAllProperties();
1117bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        return mAdapterProperties.get(name);
11189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1120d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized String getAddress() {
1121d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1122d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return getProperty("Address");
11239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1125d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized String getName() {
11269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1127d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return getProperty("Name");
11289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1131d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Returns the user-friendly name of a remote device.  This value is
1132d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * returned from our local cache, which is updated when onPropertyChange
1133d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * event is received.
1134d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Do not expect to retrieve the updated remote name immediately after
1135d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * changing the name on the remote device.
11369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1137d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * @param address Bluetooth address of remote device.
1138d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     *
1139d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * @return The user-friendly name of the specified remote device.
11409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1141d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized String getRemoteName(String address) {
1142d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1143005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1144d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return null;
1145d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
114655929a958bf0e482c8e4d7df3dd75957f1e9d871Jaikumar Ganesh        return getRemoteDeviceProperty(address, "Name");
11479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
11509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Get the discoverability window for the device.  A timeout of zero
11519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * means that the device is permanently discoverable (if the device is
11529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * in the discoverable mode).
11539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
11549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The discoverability window of the device, in seconds.  A negative
11559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         value indicates an error.
11569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
11579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized int getDiscoverableTimeout() {
11589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1159d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String timeout = getProperty("DiscoverableTimeout");
1160d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (timeout != null)
1161d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh           return Integer.valueOf(timeout);
1162d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        else
1163d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return -1;
11649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized int getScanMode() {
11679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
11688c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal())
1169de893f550301a60274e87aa8168225e7a7a42184Nick Pelly            return BluetoothAdapter.SCAN_MODE_NONE;
1170d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1171d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        boolean pairable = getProperty("Pairable").equals("true");
1172d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        boolean discoverable = getProperty("Discoverable").equals("true");
1173d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return bluezStringToScanMode (pairable, discoverable);
11749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1176d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized boolean startDiscovery() {
11779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
11789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
11798c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
11808c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1181d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return startDiscoveryNative();
11829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1184d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized boolean cancelDiscovery() {
11859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
11869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
11878c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
11888c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1189d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return stopDiscoveryNative();
1190d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
1191d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1192d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized boolean isDiscovering() {
1193d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1194d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return mIsDiscovering;
1195d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
1196d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1197d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ void setIsDiscovering(boolean isDiscovering) {
1198d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mIsDiscovering = isDiscovering;
11999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1201cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    private boolean isBondingFeasible(String address) {
12029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
12039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
12048c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
12058c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1206005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
12079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
12089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        address = address.toUpperCase();
12109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12112092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        if (mBondState.getPendingOutgoingBonding() != null) {
12129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            log("Ignoring createBond(): another device is bonding");
12139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // a different device is currently bonding, fail
12149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
12159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Check for bond state only if we are not performing auto
12189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // pairing exponential back-off attempts.
12199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mBondState.isAutoPairingAttemptsInProgress(address) &&
1220005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly                mBondState.getBondState(address) != BluetoothDevice.BOND_NONE) {
12219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            log("Ignoring createBond(): this device is already bonding or bonded");
12229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
12239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12253fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        if (address.equals(mDockAddress)) {
12263fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            if (!writeDockPin()) {
12273fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                log("Error while writing Pin for the dock");
12283fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                return false;
12293fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            }
12303fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        }
1231cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        return true;
1232cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    }
12333fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
1234cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    public synchronized boolean createBond(String address) {
1235cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (!isBondingFeasible(address)) return false;
1236cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
1237cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (!createPairedDeviceNative(address, 60000  /*1 minute*/ )) {
12389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
12399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12412092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        mBondState.setPendingOutgoingBonding(address);
12429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mBondState.setBondState(address, BluetoothDevice.BOND_BONDING);
12432092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
12449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
12459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1247cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    public synchronized boolean createBondOutOfBand(String address, byte[] hash,
1248cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh                                                    byte[] randomizer) {
1249cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (!isBondingFeasible(address)) return false;
1250cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
1251cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (!createPairedDeviceOutOfBandNative(address, 60000 /* 1 minute */)) {
1252cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh            return false;
1253cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        }
1254cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
1255cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        setDeviceOutOfBandData(address, hash, randomizer);
1256cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        mBondState.setPendingOutgoingBonding(address);
1257cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        mBondState.setBondState(address, BluetoothDevice.BOND_BONDING);
1258cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
1259cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        return true;
1260cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    }
1261cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
1262cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    public synchronized boolean setDeviceOutOfBandData(String address, byte[] hash,
1263cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh            byte[] randomizer) {
1264cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1265cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh                                                "Need BLUETOOTH_ADMIN permission");
1266cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (!isEnabledInternal()) return false;
1267cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
1268cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        Pair <byte[], byte[]> value = new Pair<byte[], byte[]>(hash, randomizer);
1269cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
1270cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (DBG) {
1271cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh            log("Setting out of band data for:" + address + ":" +
1272cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh              Arrays.toString(hash) + ":" + Arrays.toString(randomizer));
1273cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        }
1274cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
1275cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        mDeviceOobData.put(address, value);
1276cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        return true;
1277cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    }
1278cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
1279cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    Pair<byte[], byte[]> getDeviceOutOfBandData(BluetoothDevice device) {
1280cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        return mDeviceOobData.get(device.getAddress());
1281cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    }
1282cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
1283cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
1284cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    public synchronized byte[] readOutOfBandData() {
1285cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
1286cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh                                                "Need BLUETOOTH permission");
1287cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (!isEnabledInternal()) return null;
1288cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
1289cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        return readAdapterOutOfBandDataNative();
1290cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    }
1291cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
12929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean cancelBondProcess(String address) {
12939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
12949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
12958c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
12968c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1297005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
12989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
12999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        address = address.toUpperCase();
13019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mBondState.getBondState(address) != BluetoothDevice.BOND_BONDING) {
13029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
13039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1305005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        mBondState.setBondState(address, BluetoothDevice.BOND_NONE,
13069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
1307d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        cancelDeviceCreationNative(address);
13089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
13099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean removeBond(String address) {
13129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
13139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
13148c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
13158c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1316005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
13179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
13189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1319f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
13209b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (state != null) {
1321f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            state.sendMessage(BluetoothDeviceProfileState.UNPAIR);
13229b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            return true;
13239b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        } else {
13249b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            return false;
13259b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
13269b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
13279b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
13289b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public synchronized boolean removeBondInternal(String address) {
1329d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return removeDeviceNative(getObjectPathFromAddress(address));
13309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized String[] listBonds() {
13339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
13349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mBondState.listInState(BluetoothDevice.BOND_BONDED);
13359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1337a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    /*package*/ synchronized String[] listInState(int state) {
1338a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh      return mBondState.listInState(state);
1339a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    }
1340a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh
13419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized int getBondState(String address) {
13429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1343005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1344b24e11baac589fe16426f2d243b460ab84991c7bNick Pelly            return BluetoothDevice.ERROR;
13459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mBondState.getBondState(address.toUpperCase());
13479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1349a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    /*package*/ synchronized boolean setBondState(String address, int state) {
1350a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        return setBondState(address, state, 0);
1351a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    }
1352a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh
1353a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    /*package*/ synchronized boolean setBondState(String address, int state, int reason) {
1354a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        mBondState.setBondState(address.toUpperCase(), state);
1355a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        return true;
1356a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    }
1357a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh
13583fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    public synchronized boolean isBluetoothDock(String address) {
13596e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh        SharedPreferences sp = mContext.getSharedPreferences(SHARED_PREFERENCES_NAME,
13606e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                mContext.MODE_PRIVATE);
13616e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh
13626e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh        return sp.contains(SHARED_PREFERENCE_DOCK_ADDRESS + address);
13633fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    }
13643fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
13659488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh    /*package*/ boolean isRemoteDeviceInCache(String address) {
1366bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        return (mDeviceProperties.get(address) != null);
13679488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh    }
13689488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh
13699488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh    /*package*/ String[] getRemoteDeviceProperties(String address) {
13708c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return null;
13718c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
13729488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh        String objectPath = getObjectPathFromAddress(address);
13739488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh        return (String [])getDevicePropertiesNative(objectPath);
13749488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh    }
13759488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh
1376d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /*package*/ synchronized String getRemoteDeviceProperty(String address, String property) {
1377bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        Map<String, String> properties = mDeviceProperties.get(address);
1378d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (properties != null) {
1379d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return properties.get(property);
1380d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        } else {
1381d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            // Query for remote device properties, again.
1382d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            // We will need to reload the cache when we switch Bluetooth on / off
1383d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            // or if we crash.
138410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            if (updateRemoteDevicePropertiesCache(address))
1385d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                return getRemoteDeviceProperty(address, property);
13869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1387d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        Log.e(TAG, "getRemoteDeviceProperty: " + property + "not present:" + address);
1388d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return null;
13899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
139110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh    /* package */ synchronized boolean updateRemoteDevicePropertiesCache(String address) {
139210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        String[] propValues = getRemoteDeviceProperties(address);
139310eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        if (propValues != null) {
139410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            addRemoteDeviceProperties(address, propValues);
139510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            return true;
139610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        }
139710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        return false;
139810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh    }
139910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
1400d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ synchronized void addRemoteDeviceProperties(String address, String[] properties) {
1401395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh        /*
1402395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh         * We get a DeviceFound signal every time RSSI changes or name changes.
1403395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh         * Don't create a new Map object every time */
1404bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        Map<String, String> propertyValues = mDeviceProperties.get(address);
1405efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh        if (propertyValues == null) {
1406395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh            propertyValues = new HashMap<String, String>();
1407395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh        }
1408395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh
14098bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh        for (int i = 0; i < properties.length; i++) {
14108bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            String name = properties[i];
1411efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh            String newValue = null;
14128bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            int len;
14138bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            if (name == null) {
14148bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                Log.e(TAG, "Error: Remote Device Property at index" + i + "is null");
14158bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                continue;
14168bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            }
14178bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            if (name.equals("UUIDs") || name.equals("Nodes")) {
1418efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                StringBuilder str = new StringBuilder();
14198bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                len = Integer.valueOf(properties[++i]);
14208bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                for (int j = 0; j < len; j++) {
1421efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                    str.append(properties[++i]);
1422efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                    str.append(",");
1423efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                }
1424efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                if (len > 0) {
1425efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                    newValue = str.toString();
14268bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                }
1427d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            } else {
14288bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                newValue = properties[++i];
1429d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            }
1430efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh
14318bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            propertyValues.put(name, newValue);
14329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1433bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mDeviceProperties.put(address, propertyValues);
143410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
143510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        // We have added a new remote device or updated its properties.
143610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        // Also update the serviceChannel cache.
143710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        updateDeviceServiceChannelCache(address);
14389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1440d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ void removeRemoteDeviceProperties(String address) {
1441bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mDeviceProperties.remove(address);
14429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1444d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ synchronized void setRemoteDeviceProperty(String address, String name,
1445d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                                                              String value) {
1446bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        Map <String, String> propVal = mDeviceProperties.get(address);
1447d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (propVal != null) {
1448d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            propVal.put(name, value);
1449bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            mDeviceProperties.put(address, propVal);
1450d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        } else {
1451d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            Log.e(TAG, "setRemoteDeviceProperty for a device not in cache:" + address);
14529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
14539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1456efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * Sets the remote device trust state.
1457efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     *
1458efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * @return boolean to indicate operation success or fail
1459efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     */
1460efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    public synchronized boolean setTrust(String address, boolean value) {
1461005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1462e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly            mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1463e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly                    "Need BLUETOOTH_ADMIN permission");
1464efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            return false;
1465efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        }
1466efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue
14678c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
14688c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1469efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        return setDevicePropertyBooleanNative(getObjectPathFromAddress(address), "Trusted",
1470efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue                value ? 1 : 0);
1471efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    }
1472efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue
1473efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    /**
1474efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * Gets the remote device trust state as boolean.
1475efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * Note: this value may be
1476efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * retrieved from cache if we retrieved the data before *
1477efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     *
1478efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * @return boolean to indicate trust or untrust state
1479efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     */
1480efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    public synchronized boolean getTrustState(String address) {
1481005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1482efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1483efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            return false;
1484efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        }
1485efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue
1486efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        String val = getRemoteDeviceProperty(address, "Trusted");
1487efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        if (val == null) {
1488efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            return false;
1489efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        } else {
1490efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            return val.equals("true") ? true : false;
1491efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        }
1492efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    }
1493efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue
1494efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    /**
1495d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Gets the remote major, minor classes encoded as a 32-bit
14969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * integer.
14979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
14989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Note: this value is retrieved from cache, because we get it during
14999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *       remote-device discovery.
15009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
15019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return 32-bit integer encoding the remote major, minor, and service
15029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         classes.
15039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
15049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized int getRemoteClass(String address) {
1505005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1506ea600ccfb7568f60377c4abc85f56c80af7fdbfcNick Pelly            mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1507ea600ccfb7568f60377c4abc85f56c80af7fdbfcNick Pelly            return BluetoothClass.ERROR;
15089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1509d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String val = getRemoteDeviceProperty(address, "Class");
1510d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (val == null)
1511d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return BluetoothClass.ERROR;
1512d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        else {
1513d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return Integer.valueOf(val);
1514d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
15159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1516d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
15179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1519dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh     * Gets the UUIDs supported by the remote device
15209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1521dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh     * @return array of 128bit ParcelUuids
15229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1523dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh    public synchronized ParcelUuid[] getRemoteUuids(String address) {
15249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1525005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
15269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return null;
15279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
15281caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        return getUuidFromCache(address);
15291caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    }
15301caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
15311caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    private ParcelUuid[] getUuidFromCache(String address) {
1532d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String value = getRemoteDeviceProperty(address, "UUIDs");
1533dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        if (value == null) return null;
1534dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh
1535dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        String[] uuidStrings = null;
1536d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        // The UUIDs are stored as a "," separated string.
1537dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        uuidStrings = value.split(",");
1538dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        ParcelUuid[] uuids = new ParcelUuid[uuidStrings.length];
1539dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh
1540dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        for (int i = 0; i < uuidStrings.length; i++) {
1541dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh            uuids[i] = ParcelUuid.fromString(uuidStrings[i]);
1542dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        }
1543d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return uuids;
15449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
15459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
154616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    /**
154716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * Connect and fetch new UUID's using SDP.
154816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * The UUID's found are broadcast as intents.
154916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * Optionally takes a uuid and callback to fetch the RFCOMM channel for the
155016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * a given uuid.
155116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * TODO: Don't wait UUID_INTENT_DELAY to broadcast UUID intents on success
155216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * TODO: Don't wait UUID_INTENT_DELAY to handle the failure case for
155316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * callback and broadcast intents.
155416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     */
155516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    public synchronized boolean fetchRemoteUuids(String address, ParcelUuid uuid,
155616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            IBluetoothCallback callback) {
15571caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
15588c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
15598c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
15601caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
15611caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            return false;
15621caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        }
15631caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
156416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        RemoteService service = new RemoteService(address, uuid);
156516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        if (uuid != null && mUuidCallbackTracker.get(service) != null) {
156616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            // An SDP query for this address & uuid is already in progress
156716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            // Do not add this callback for the uuid
156816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            return false;
156916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
157016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
15711caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        if (mUuidIntentTracker.contains(address)) {
15721caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            // An SDP query for this address is already in progress
157316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            // Add this uuid onto the in-progress SDP query
157416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (uuid != null) {
157516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                mUuidCallbackTracker.put(new RemoteService(address, uuid), callback);
157616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
15771caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            return true;
15781caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        }
15791caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
15801caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        boolean ret;
15810e09030977aea8b40fd177139528d4b5637c9771Jaikumar Ganesh        // Just do the SDP if the device is already  created and UUIDs are not
15820e09030977aea8b40fd177139528d4b5637c9771Jaikumar Ganesh        // NULL, else create the device and then do SDP.
15830e09030977aea8b40fd177139528d4b5637c9771Jaikumar Ganesh        if (isRemoteDeviceInCache(address) && getRemoteUuids(address) != null) {
15841caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            String path = getObjectPathFromAddress(address);
15851caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            if (path == null) return false;
15861caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
15871caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            // Use an empty string for the UUID pattern
15881caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            ret = discoverServicesNative(path, "");
15891caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        } else {
15901caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            ret = createDeviceNative(address);
15911caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        }
15921caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
15931caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        mUuidIntentTracker.add(address);
159416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        if (uuid != null) {
159516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            mUuidCallbackTracker.put(new RemoteService(address, uuid), callback);
159616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
15971caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
15981caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        Message message = mHandler.obtainMessage(MESSAGE_UUID_INTENT);
15991caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        message.obj = address;
16001caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        mHandler.sendMessageDelayed(message, UUID_INTENT_DELAY);
16011caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        return ret;
16021caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    }
16031caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
16049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1605d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Gets the rfcomm channel associated with the UUID.
160616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * Pulls records from the cache only.
16079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1608d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * @param address Address of the remote device
1609dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh     * @param uuid ParcelUuid of the service attribute
16109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1611d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * @return rfcomm channel associated with the service attribute
161210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh     *         -1 on error
16139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1614dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh    public int getRemoteServiceChannel(String address, ParcelUuid uuid) {
16159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
16168c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return -1;
16178c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1618005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1619b24e11baac589fe16426f2d243b460ab84991c7bNick Pelly            return BluetoothDevice.ERROR;
16209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
162110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        // Check if we are recovering from a crash.
162210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        if (mDeviceProperties.isEmpty()) {
162310eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            if (!updateRemoteDevicePropertiesCache(address))
162410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh                return -1;
162510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        }
162610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
162710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        Map<ParcelUuid, Integer> value = mDeviceServiceChannelCache.get(address);
162810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        if (value != null && value.containsKey(uuid))
162910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            return value.get(uuid);
163010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        return -1;
16319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
16329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean setPin(String address, byte[] pin) {
16349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
16359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
16368c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
16378c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
16389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (pin == null || pin.length <= 0 || pin.length > 16 ||
1639005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            !BluetoothAdapter.checkBluetoothAddress(address)) {
16409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
16419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
16429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        address = address.toUpperCase();
16439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
16449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (data == null) {
16459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.w(TAG, "setPin(" + address + ") called but no native data available, " +
16469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                  "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
16479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                  " or by bluez.\n");
16489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
16499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
16509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // bluez API wants pin as a string
16519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String pinString;
16529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
16539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pinString = new String(pin, "UTF8");
16549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (UnsupportedEncodingException uee) {
16559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.e(TAG, "UTF8 not supported?!?");
16569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
16579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
16589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return setPinNative(address, pinString, data.intValue());
16599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
16609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1661b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    public synchronized boolean setPasskey(String address, int passkey) {
1662b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1663b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                                                "Need BLUETOOTH_ADMIN permission");
16648c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
16658c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1666005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (passkey < 0 || passkey > 999999 || !BluetoothAdapter.checkBluetoothAddress(address)) {
1667b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            return false;
1668b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        }
1669b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        address = address.toUpperCase();
1670b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
1671b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        if (data == null) {
1672b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            Log.w(TAG, "setPasskey(" + address + ") called but no native data available, " +
1673b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                  "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
1674b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                  " or by bluez.\n");
1675b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            return false;
1676b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        }
1677b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        return setPasskeyNative(address, passkey, data.intValue());
1678b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    }
1679b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh
1680b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    public synchronized boolean setPairingConfirmation(String address, boolean confirm) {
1681b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1682b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                                                "Need BLUETOOTH_ADMIN permission");
16838c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
16848c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1685b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        address = address.toUpperCase();
1686b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
1687b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        if (data == null) {
1688b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            Log.w(TAG, "setPasskey(" + address + ") called but no native data available, " +
1689b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                  "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
1690b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                  " or by bluez.\n");
1691b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            return false;
1692b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        }
1693b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        return setPairingConfirmationNative(address, confirm, data.intValue());
1694b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    }
1695b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh
1696cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    public synchronized boolean setRemoteOutOfBandData(String address) {
1697cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1698cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh                                                "Need BLUETOOTH_ADMIN permission");
1699cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (!isEnabledInternal()) return false;
1700cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        address = address.toUpperCase();
1701cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
1702cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (data == null) {
1703cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh            Log.w(TAG, "setRemoteOobData(" + address + ") called but no native data available, " +
1704cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh                  "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
1705cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh                  " or by bluez.\n");
1706cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh            return false;
1707cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        }
1708cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
1709cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        Pair<byte[], byte[]> val = mDeviceOobData.get(address);
1710cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        byte[] hash, randomizer;
1711cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (val == null) {
1712cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh            // TODO: check what should be passed in this case.
1713cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh            hash = new byte[16];
1714cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh            randomizer = new byte[16];
1715cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        } else {
1716cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh            hash = val.first;
1717cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh            randomizer = val.second;
1718cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        }
1719cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        return setRemoteOutOfBandDataNative(address, hash, randomizer, data.intValue());
1720cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    }
1721cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
1722b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    public synchronized boolean cancelPairingUserInput(String address) {
17239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
17249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
17258c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
17268c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1727005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
17289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
17299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1730005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        mBondState.setBondState(address, BluetoothDevice.BOND_NONE,
1731397d8f4f4829a45f4fe7a672cc395466bbc0f442Jaikumar Ganesh                BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
17329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        address = address.toUpperCase();
17339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
17349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (data == null) {
1735b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            Log.w(TAG, "cancelUserInputNative(" + address + ") called but no native data " +
1736b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                "available, ignoring. Maybe the PasskeyAgent Request was already cancelled " +
1737b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                "by the remote or by bluez.\n");
17389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
17399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1740b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        return cancelPairingUserInputNative(address, data.intValue());
17419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
17429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17438c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh    /*package*/ void updateDeviceServiceChannelCache(String address) {
174410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        ParcelUuid[] deviceUuids = getRemoteUuids(address);
174510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        // We are storing the rfcomm channel numbers only for the uuids
174610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        // we are interested in.
174710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        int channel;
174816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        if (DBG) log("updateDeviceServiceChannelCache(" + address + ")");
174916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
175016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        ArrayList<ParcelUuid> applicationUuids = new ArrayList();
175116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
175216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        synchronized (this) {
175316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            for (RemoteService service : mUuidCallbackTracker.keySet()) {
175416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (service.address.equals(address)) {
175516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    applicationUuids.add(service.uuid);
175616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                }
175716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
175816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
175910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
176010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        Map <ParcelUuid, Integer> value = new HashMap<ParcelUuid, Integer>();
176116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
176216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        // Retrieve RFCOMM channel for default uuids
176316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        for (ParcelUuid uuid : RFCOMM_UUIDS) {
176410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            if (BluetoothUuid.isUuidPresent(deviceUuids, uuid)) {
176516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                channel = getDeviceServiceChannelNative(getObjectPathFromAddress(address),
176616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        uuid.toString(), 0x0004);
176716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (DBG) log("\tuuid(system): " + uuid + " " + channel);
176810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh                value.put(uuid, channel);
176910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            }
177010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        }
177116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        // Retrieve RFCOMM channel for application requested uuids
177216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        for (ParcelUuid uuid : applicationUuids) {
177316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (BluetoothUuid.isUuidPresent(deviceUuids, uuid)) {
177416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                channel = getDeviceServiceChannelNative(getObjectPathFromAddress(address),
177516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        uuid.toString(), 0x0004);
177616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (DBG) log("\tuuid(application): " + uuid + " " + channel);
177716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                value.put(uuid, channel);
177816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
177916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
178016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
178116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        synchronized (this) {
178216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            // Make application callbacks
178316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            for (Iterator<RemoteService> iter = mUuidCallbackTracker.keySet().iterator();
178416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    iter.hasNext();) {
178516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                RemoteService service = iter.next();
178616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (service.address.equals(address)) {
178716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    channel = -1;
178816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    if (value.get(service.uuid) != null) {
178916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        channel = value.get(service.uuid);
179016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    }
179116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    if (channel != -1) {
179216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        if (DBG) log("Making callback for " + service.uuid + " with result " +
179316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                                channel);
179416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        IBluetoothCallback callback = mUuidCallbackTracker.get(service);
179516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        if (callback != null) {
179616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                            try {
179716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                                callback.onRfcommChannelFound(channel);
179816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                            } catch (RemoteException e) {Log.e(TAG, "", e);}
179916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        }
180016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
180116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        iter.remove();
180216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    }
180316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                }
180416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
180516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
180616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            // Update cache
180716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            mDeviceServiceChannelCache.put(address, value);
180816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
180910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh    }
181010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
181124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    /**
181224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     * b is a handle to a Binder instance, so that this service can be notified
181324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     * for Applications that terminate unexpectedly, to clean there service
181424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     * records
181524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     */
181624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    public synchronized int addRfcommServiceRecord(String serviceName, ParcelUuid uuid,
181724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            int channel, IBinder b) {
18188c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
18198c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return -1;
18208c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
182124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (serviceName == null || uuid == null || channel < 1 ||
182224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                channel > BluetoothSocket.MAX_RFCOMM_CHANNEL) {
182324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            return -1;
182424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
182524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (BluetoothUuid.isUuidPresent(BluetoothUuid.RESERVED_UUIDS, uuid)) {
182624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            Log.w(TAG, "Attempted to register a reserved UUID: " + uuid);
182724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            return -1;
182824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
182924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        int handle = addRfcommServiceRecordNative(serviceName,
183024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                uuid.getUuid().getMostSignificantBits(), uuid.getUuid().getLeastSignificantBits(),
183124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                (short)channel);
183224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (DBG) log("new handle " + Integer.toHexString(handle));
183324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (handle == -1) {
183424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            return -1;
183524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
183624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
183724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        int pid = Binder.getCallingPid();
183824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        mServiceRecordToPid.put(new Integer(handle), new Integer(pid));
183924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        try {
184024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            b.linkToDeath(new Reaper(handle, pid), 0);
184124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        } catch (RemoteException e) {}
184224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        return handle;
184324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    }
184424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
184524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    public void removeServiceRecord(int handle) {
184624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
184724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                                                "Need BLUETOOTH permission");
184824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        checkAndRemoveRecord(handle, Binder.getCallingPid());
184924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    }
185024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
185124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private synchronized void checkAndRemoveRecord(int handle, int pid) {
185224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        Integer handleInt = new Integer(handle);
185324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        Integer owner = mServiceRecordToPid.get(handleInt);
185424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (owner != null && pid == owner.intValue()) {
185524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            if (DBG) log("Removing service record " + Integer.toHexString(handle) + " for pid " +
185624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                    pid);
185724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            mServiceRecordToPid.remove(handleInt);
185824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            removeServiceRecordNative(handle);
185924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
186024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    }
186124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
186224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private class Reaper implements IBinder.DeathRecipient {
186324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        int pid;
186424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        int handle;
186524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        Reaper(int handle, int pid) {
186624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            this.pid = pid;
186724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            this.handle = handle;
186824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
186924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        public void binderDied() {
187024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            synchronized (BluetoothService.this) {
187124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                if (DBG) log("Tracked app " + pid + " died");
187224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                checkAndRemoveRecord(handle, pid);
187324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            }
187424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
187524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    }
187624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
18779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
18789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
18799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onReceive(Context context, Intent intent) {
18806e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh            if (intent == null) return;
18816e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh
18829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String action = intent.getAction();
18839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
18849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ContentResolver resolver = context.getContentResolver();
18859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Query the airplane mode from Settings.System just to make sure that
18869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // some random app is not sending this intent and disabling bluetooth
18879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                boolean enabled = !isAirplaneModeOn();
18889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // If bluetooth is currently expected to be on, then enable or disable bluetooth
18899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (Settings.Secure.getInt(resolver, Settings.Secure.BLUETOOTH_ON, 0) > 0) {
18909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (enabled) {
1891105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                        enable(false);
18929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } else {
18939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        disable(false);
18949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
18959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
18966e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh            } else if (Intent.ACTION_DOCK_EVENT.equals(action)) {
18976e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                int state = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
18986e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                        Intent.EXTRA_DOCK_STATE_UNDOCKED);
18996e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                if (DBG) Log.v(TAG, "Received ACTION_DOCK_EVENT with State:" + state);
19006e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                if (state == Intent.EXTRA_DOCK_STATE_UNDOCKED) {
19016e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                    mDockAddress = null;
19026e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                    mDockPin = null;
19036e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                } else {
19046e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                    SharedPreferences.Editor editor =
19056e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                        mContext.getSharedPreferences(SHARED_PREFERENCES_NAME,
19066e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                                mContext.MODE_PRIVATE).edit();
19076e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                    editor.putBoolean(SHARED_PREFERENCE_DOCK_ADDRESS + mDockAddress, true);
190866fce5068a8a3aeb28aaf713843891b286a75280Brad Fitzpatrick                    editor.apply();
19096e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                }
19109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
19119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
19129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
19139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19146e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh    private void registerForAirplaneMode(IntentFilter filter) {
191544303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        final ContentResolver resolver = mContext.getContentResolver();
191644303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        final String airplaneModeRadios = Settings.System.getString(resolver,
19179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Settings.System.AIRPLANE_MODE_RADIOS);
191844303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        final String toggleableRadios = Settings.System.getString(resolver,
191944303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey                Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
192044303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey
192144303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        mIsAirplaneSensitive = airplaneModeRadios == null ? true :
192244303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey                airplaneModeRadios.contains(Settings.System.RADIO_BLUETOOTH);
192344303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        mIsAirplaneToggleable = toggleableRadios == null ? false :
192444303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey                toggleableRadios.contains(Settings.System.RADIO_BLUETOOTH);
192544303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey
19269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mIsAirplaneSensitive) {
19276e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh            filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
19289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
19299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
19309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* Returns true if airplane mode is currently on */
19329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final boolean isAirplaneModeOn() {
19339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return Settings.System.getInt(mContext.getContentResolver(),
19349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Settings.System.AIRPLANE_MODE_ON, 0) == 1;
19359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
19369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19371caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    /* Broadcast the Uuid intent */
19381caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    /*package*/ synchronized void sendUuidIntent(String address) {
19396179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh        ParcelUuid[] uuid = getUuidFromCache(address);
19406179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh        Intent intent = new Intent(BluetoothDevice.ACTION_UUID);
19412d3b98d868cda30535505b2a2fba47aa1c9c052bJaikumar Ganesh        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
19426179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh        intent.putExtra(BluetoothDevice.EXTRA_UUID, uuid);
19436179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh        mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
19441caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
19456179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh        if (mUuidIntentTracker.contains(address))
19461caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            mUuidIntentTracker.remove(address);
194716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
194816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    }
194916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
195016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    /*package*/ synchronized void makeServiceChannelCallbacks(String address) {
195116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        for (Iterator<RemoteService> iter = mUuidCallbackTracker.keySet().iterator();
195216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                iter.hasNext();) {
195316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            RemoteService service = iter.next();
195416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (service.address.equals(address)) {
195516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (DBG) log("Cleaning up failed UUID channel lookup: " + service.address +
195616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        " " + service.uuid);
195716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                IBluetoothCallback callback = mUuidCallbackTracker.get(service);
195816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (callback != null) {
195916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    try {
196016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        callback.onRfcommChannelFound(-1);
196116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    } catch (RemoteException e) {Log.e(TAG, "", e);}
196216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                }
196316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
196416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                iter.remove();
196516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
196616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
19671caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    }
19681caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
19699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
19709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1971105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        switch(mBluetoothState) {
1972de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_OFF:
197324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            pw.println("Bluetooth OFF\n");
1974105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return;
1975de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_TURNING_ON:
197624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            pw.println("Bluetooth TURNING ON\n");
1977105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return;
1978de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_TURNING_OFF:
197924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            pw.println("Bluetooth TURNING OFF\n");
1980105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return;
1981de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_ON:
198224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            pw.println("Bluetooth ON\n");
1983105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
1984105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
198524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("mIsAirplaneSensitive = " + mIsAirplaneSensitive);
198644303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        pw.println("mIsAirplaneToggleable = " + mIsAirplaneToggleable);
198724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
198824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("Local address = " + getAddress());
198924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("Local name = " + getName());
199024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("isDiscovering() = " + isDiscovering());
1991105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
1992105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        BluetoothHeadset headset = new BluetoothHeadset(mContext, null);
1993105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
1994105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        pw.println("\n--Known devices--");
1995bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        for (String address : mDeviceProperties.keySet()) {
19961eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly            int bondState = mBondState.getBondState(address);
1997105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            pw.printf("%s %10s (%d) %s\n", address,
19981eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly                       toBondStateString(bondState),
1999105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                       mBondState.getAttempt(address),
2000105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                       getRemoteName(address));
200124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
200224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            Map<ParcelUuid, Integer> uuidChannels = mDeviceServiceChannelCache.get(address);
200324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            if (uuidChannels == null) {
200424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                pw.println("\tuuids = null");
200524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            } else {
200624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                for (ParcelUuid uuid : uuidChannels.keySet()) {
200724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                    Integer channel = uuidChannels.get(uuid);
200824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                    if (channel == null) {
200924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                        pw.println("\t" + uuid);
201024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                    } else {
201124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                        pw.println("\t" + uuid + " RFCOMM channel = " + channel);
20121eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly                    }
20131eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly                }
20141eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly            }
201516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            for (RemoteService service : mUuidCallbackTracker.keySet()) {
201616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (service.address.equals(address)) {
201716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    pw.println("\tPENDING CALLBACK: " + service.uuid);
201816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                }
201916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
2020105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
2021105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
2022d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String value = getProperty("Devices");
20231eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly        String[] devicesObjectPath = null;
2024d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (value != null) {
2025d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            devicesObjectPath = value.split(",");
2026d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
2027105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        pw.println("\n--ACL connected devices--");
202824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (devicesObjectPath != null) {
202924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            for (String device : devicesObjectPath) {
203024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                pw.println(getAddressFromObjectPath(device));
203124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            }
2032105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
2033105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
2034105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Rather not do this from here, but no-where else and I need this
2035105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // dump
2036105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        pw.println("\n--Headset Service--");
2037740e39be6af3e366a4b82c030b5ea67ab144b42aJaikumar Ganesh        switch (headset.getState(headset.getCurrentHeadset())) {
2038105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        case BluetoothHeadset.STATE_DISCONNECTED:
2039105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            pw.println("getState() = STATE_DISCONNECTED");
2040105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            break;
2041105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        case BluetoothHeadset.STATE_CONNECTING:
2042105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            pw.println("getState() = STATE_CONNECTING");
2043105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            break;
2044105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        case BluetoothHeadset.STATE_CONNECTED:
2045105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            pw.println("getState() = STATE_CONNECTED");
2046105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            break;
2047105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        case BluetoothHeadset.STATE_ERROR:
2048105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            pw.println("getState() = STATE_ERROR");
2049105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            break;
2050105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
20516c901db72dbaf57d8fdf26adae6721de14ecae22Nick Pelly
205224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("\ngetCurrentHeadset() = " + headset.getCurrentHeadset());
205324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("getBatteryUsageHint() = " + headset.getBatteryUsageHint());
2054105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        headset.close();
205524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("\n--Application Service Records--");
205624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        for (Integer handle : mServiceRecordToPid.keySet()) {
205724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            Integer pid = mServiceRecordToPid.get(handle);
205824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            pw.println("\tpid " + pid + " handle " + Integer.toHexString(handle));
205924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
20609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
20619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2062d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ static int bluezStringToScanMode(boolean pairable, boolean discoverable) {
2063d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (pairable && discoverable)
2064bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            return BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE;
2065d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        else if (pairable && !discoverable)
2066bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            return BluetoothAdapter.SCAN_MODE_CONNECTABLE;
2067d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        else
2068bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            return BluetoothAdapter.SCAN_MODE_NONE;
20699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
20709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* package */ static String scanModeToBluezString(int mode) {
20729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        switch (mode) {
2073bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        case BluetoothAdapter.SCAN_MODE_NONE:
20749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "off";
2075bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
20769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "connectable";
2077bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
20789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "discoverable";
20799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
20809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return null;
20819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
20829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2083d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /*package*/ String getAddressFromObjectPath(String objectPath) {
2084b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh        String adapterObjectPath = getPropertyInternal("ObjectPath");
2085d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (adapterObjectPath == null || objectPath == null) {
2086d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            Log.e(TAG, "getAddressFromObjectPath: AdpaterObjectPath:" + adapterObjectPath +
2087d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                    "  or deviceObjectPath:" + objectPath + " is null");
2088d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return null;
2089d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
2090d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (!objectPath.startsWith(adapterObjectPath)) {
2091d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            Log.e(TAG, "getAddressFromObjectPath: AdpaterObjectPath:" + adapterObjectPath +
2092d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                    "  is not a prefix of deviceObjectPath:" + objectPath +
2093d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                    "bluetoothd crashed ?");
2094d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return null;
2095d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
2096d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String address = objectPath.substring(adapterObjectPath.length());
2097d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (address != null) return address.replace('_', ':');
2098d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
2099d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        Log.e(TAG, "getAddressFromObjectPath: Address being returned is null");
2100d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return null;
2101d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
2102d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
2103d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /*package*/ String getObjectPathFromAddress(String address) {
2104b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh        String path = getPropertyInternal("ObjectPath");
2105d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (path == null) {
2106d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            Log.e(TAG, "Error: Object Path is null");
2107d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return null;
2108d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
2109d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        path = path + address.replace(":", "_");
2110d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return path;
2111d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
2112d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
2113b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh    /*package */ void setLinkTimeout(String address, int num_slots) {
2114b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh        String path = getObjectPathFromAddress(address);
2115b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh        boolean result = setLinkTimeoutNative(path, num_slots);
2116b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh
2117b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh        if (!result) log("Set Link Timeout to:" + num_slots + " slots failed");
2118b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh    }
2119b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh
21209b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public boolean connectHeadset(String address) {
2121f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
21229b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (state != null) {
2123f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            Message msg = new Message();
2124f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.arg1 = BluetoothDeviceProfileState.CONNECT_HFP_OUTGOING;
2125f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.obj = state;
2126f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            mHfpProfileState.sendMessage(msg);
2127f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            return true;
21289b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
21299b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        return false;
21309b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
21319b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
21329b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public boolean disconnectHeadset(String address) {
2133f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
21349b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (state != null) {
2135f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            Message msg = new Message();
2136f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.arg1 = BluetoothDeviceProfileState.DISCONNECT_HFP_OUTGOING;
2137f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.obj = state;
2138f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            mHfpProfileState.sendMessage(msg);
21399b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            return true;
21409b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
21419b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        return false;
21429b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
21439b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
21449b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public boolean connectSink(String address) {
2145f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
21469b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (state != null) {
2147f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            Message msg = new Message();
2148f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.arg1 = BluetoothDeviceProfileState.CONNECT_A2DP_OUTGOING;
2149f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.obj = state;
2150f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            mA2dpProfileState.sendMessage(msg);
2151f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            return true;
21529b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
21539b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        return false;
21549b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
21559b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
21569b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public boolean disconnectSink(String address) {
2157f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
21589b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (state != null) {
2159f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            Message msg = new Message();
2160f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.arg1 = BluetoothDeviceProfileState.DISCONNECT_A2DP_OUTGOING;
2161f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.obj = state;
2162f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            mA2dpProfileState.sendMessage(msg);
21639b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            return true;
21649b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
21659b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        return false;
21669b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
21679b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
2168f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh    private BluetoothDeviceProfileState addProfileState(String address) {
2169f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
21709b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (state != null) return state;
21719b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
2172f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        state = new BluetoothDeviceProfileState(mContext, address, this, mA2dpService);
2173f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        mDeviceProfileState.put(address, state);
21749b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        state.start();
21759b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        return state;
21769b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
21779b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
21789b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    private void removeProfileState(String address) {
2179f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        mDeviceProfileState.remove(address);
21809b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
21819b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
21829b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    private void initProfileState() {
21839b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        String []bonds = null;
21849b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        String val = getPropertyInternal("Devices");
21859b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (val != null) {
21869b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            bonds = val.split(",");
21879b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
21889b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (bonds == null) {
21899b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            return;
21909b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
21919b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
21929b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        for (String path : bonds) {
21939b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            String address = getAddressFromObjectPath(path);
2194f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            BluetoothDeviceProfileState state = addProfileState(address);
21959b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            // Allow 8 secs for SDP records to get registered.
21969b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            Message msg = new Message();
2197f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.what = BluetoothDeviceProfileState.AUTO_CONNECT_PROFILES;
21989b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            state.sendMessageDelayed(msg, 8000);
21999b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
22009b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
22019b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
22029b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public boolean notifyIncomingConnection(String address) {
2203f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        BluetoothDeviceProfileState state =
2204f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh             mDeviceProfileState.get(address);
22059b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (state != null) {
22069b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            Message msg = new Message();
2207f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.what = BluetoothDeviceProfileState.CONNECT_HFP_INCOMING;
22089b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            state.sendMessage(msg);
22099b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            return true;
22109b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
22119b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        return false;
22129b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
22139b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
22149b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    /*package*/ boolean notifyIncomingA2dpConnection(String address) {
2215f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh       BluetoothDeviceProfileState state =
2216f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            mDeviceProfileState.get(address);
22179b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh       if (state != null) {
22189b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh           Message msg = new Message();
2219f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh           msg.what = BluetoothDeviceProfileState.CONNECT_A2DP_INCOMING;
22209b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh           state.sendMessage(msg);
22219b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh           return true;
22229b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh       }
22239b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh       return false;
22249b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
22259b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
22269b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    /*package*/ void setA2dpService(BluetoothA2dpService a2dpService) {
22279b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        mA2dpService = a2dpService;
22289b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
22299b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
22309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static void log(String msg) {
22319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Log.d(TAG, msg);
22329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2233d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
2234d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native static void classInitNative();
2235d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native void initializeNativeDataNative();
2236d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setupNativeDataNative();
2237d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean tearDownNativeDataNative();
2238d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native void cleanupNativeDataNative();
2239d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native String getAdapterPathNative();
2240d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
2241d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native int isEnabledNative();
2242d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native int enableNative();
2243d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native int disableNative();
2244d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
2245d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native Object[] getAdapterPropertiesNative();
2246d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native Object[] getDevicePropertiesNative(String objectPath);
2247d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setAdapterPropertyStringNative(String key, String value);
2248d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setAdapterPropertyIntegerNative(String key, int value);
2249d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setAdapterPropertyBooleanNative(String key, int value);
2250d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
2251d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean startDiscoveryNative();
2252d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean stopDiscoveryNative();
2253d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
2254d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean createPairedDeviceNative(String address, int timeout_ms);
2255cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    private native boolean createPairedDeviceOutOfBandNative(String address, int timeout_ms);
2256cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    private native byte[] readAdapterOutOfBandDataNative();
2257cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
2258d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean cancelDeviceCreationNative(String address);
2259d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean removeDeviceNative(String objectPath);
2260d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native int getDeviceServiceChannelNative(String objectPath, String uuid,
2261d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            int attributeId);
2262d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
2263b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    private native boolean cancelPairingUserInputNative(String address, int nativeData);
2264d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setPinNative(String address, String pin, int nativeData);
2265b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    private native boolean setPasskeyNative(String address, int passkey, int nativeData);
2266b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    private native boolean setPairingConfirmationNative(String address, boolean confirm,
2267b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            int nativeData);
2268cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    private native boolean setRemoteOutOfBandDataNative(String address, byte[] hash,
2269cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh                                                        byte[] randomizer, int nativeData);
2270cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
227124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private native boolean setDevicePropertyBooleanNative(String objectPath, String key,
227224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            int value);
22731caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    private native boolean createDeviceNative(String address);
227416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    /*package*/ native boolean discoverServicesNative(String objectPath, String pattern);
227510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
227624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private native int addRfcommServiceRecordNative(String name, long uuidMsb, long uuidLsb,
227724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            short channel);
227824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private native boolean removeServiceRecordNative(int handle);
2279b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh    private native boolean setLinkTimeoutNative(String path, int num_slots);
22809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
2281