BluetoothService.java revision 740e39be6af3e366a4b82c030b5ea67ab144b42a
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;
319b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganeshimport android.bluetooth.BluetoothProfileConnectionState;
3224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pellyimport android.bluetooth.BluetoothSocket;
3310eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganeshimport android.bluetooth.BluetoothUuid;
34bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pellyimport android.bluetooth.IBluetooth;
3516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pellyimport android.bluetooth.IBluetoothCallback;
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.BroadcastReceiver;
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ContentResolver;
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Intent;
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.IntentFilter;
416e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganeshimport android.content.SharedPreferences;
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Binder;
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Handler;
443fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport android.os.IBinder;
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Message;
463fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport android.os.ParcelUuid;
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.RemoteException;
48105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Projectimport android.os.ServiceManager;
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemService;
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.Settings;
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log;
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
53d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganeshimport com.android.internal.app.IBatteryStats;
54d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
553fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.BufferedInputStream;
56c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganeshimport java.io.BufferedReader;
573fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.BufferedWriter;
58c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganeshimport java.io.DataInputStream;
59c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganeshimport java.io.File;
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileDescriptor;
613fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.FileInputStream;
623fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.FileNotFoundException;
63c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganeshimport java.io.FileOutputStream;
643fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.FileWriter;
653fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.IOException;
66c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganeshimport java.io.InputStreamReader;
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.PrintWriter;
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.UnsupportedEncodingException;
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList;
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Arrays;
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.HashMap;
7216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pellyimport java.util.Iterator;
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Map;
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
75bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pellypublic class BluetoothService extends IBluetooth.Stub {
76bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    private static final String TAG = "BluetoothService";
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final boolean DBG = true;
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mNativeData;
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private BluetoothEventLoop mEventLoop;
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mIsAirplaneSensitive;
8244303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey    private boolean mIsAirplaneToggleable;
83105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private int mBluetoothState;
84997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly    private boolean mRestart = false;  // need to call enable() after disable()
85bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    private boolean mIsDiscovering;
86997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly
87bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    private BluetoothAdapter mAdapter;  // constant after init()
88997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly    private final BondState mBondState = new BondState();  // local cache of bondings
89105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private final IBatteryStats mBatteryStats;
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final Context mContext;
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
953fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    private static final String DOCK_ADDRESS_PATH = "/sys/class/switch/dock/bt_addr";
963fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    private static final String DOCK_PIN_PATH = "/sys/class/switch/dock/bt_pin";
973fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
986e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh    private static final String SHARED_PREFERENCE_DOCK_ADDRESS = "dock_bluetooth_address";
996e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh    private static final String SHARED_PREFERENCES_NAME = "bluetooth_service_settings";
1006e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh
101105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private static final int MESSAGE_REGISTER_SDP_RECORDS = 1;
102105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private static final int MESSAGE_FINISH_DISABLE = 2;
1031caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    private static final int MESSAGE_UUID_INTENT = 3;
10412835478ee687a493d1b5882e67b6725bd539c26Nick Pelly    private static final int MESSAGE_DISCOVERABLE_TIMEOUT = 4;
1051caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
1061caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    // The timeout used to sent the UUIDs Intent
1071caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    // This timeout should be greater than the page timeout
1081caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    private static final int UUID_INTENT_DELAY = 6000;
109105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
11016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    /** Always retrieve RFCOMM channel for these SDP UUIDs */
11116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private static final ParcelUuid[] RFCOMM_UUIDS = {
11216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            BluetoothUuid.Handsfree,
11316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            BluetoothUuid.HSP,
11416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            BluetoothUuid.ObexObjectPush };
11516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
1169b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    // TODO(): Optimize all these string handling
117bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    private final Map<String, String> mAdapterProperties;
11816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private final HashMap<String, Map<String, String>> mDeviceProperties;
119d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
12016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private final HashMap<String, Map<ParcelUuid, Integer>> mDeviceServiceChannelCache;
12116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private final ArrayList<String> mUuidIntentTracker;
12216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private final HashMap<RemoteService, IBluetoothCallback> mUuidCallbackTracker;
1231caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
12424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private final HashMap<Integer, Integer> mServiceRecordToPid;
12524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
1269b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    private final HashMap<String, BluetoothProfileConnectionState> mProfileConnectionMgr;
1279b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
1289b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    private BluetoothA2dpService mA2dpService;
1293fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    private static String mDockAddress;
1303fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    private String mDockPin;
1313fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
13216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private static class RemoteService {
13316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        public String address;
13416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        public ParcelUuid uuid;
13516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        public RemoteService(String address, ParcelUuid uuid) {
13616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            this.address = address;
13716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            this.uuid = uuid;
13816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
13916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        @Override
14016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        public boolean equals(Object o) {
14116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (o instanceof RemoteService) {
14216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                RemoteService service = (RemoteService)o;
14316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                return address.equals(service.address) && uuid.equals(service.uuid);
14416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
14516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            return false;
14616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
1475f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root
1485f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root        @Override
1495f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root        public int hashCode() {
1505f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root            int hash = 1;
1515f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root            hash = hash * 31 + (address == null ? 0 : address.hashCode());
1525f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root            hash = hash * 31 + (uuid == null ? 0 : uuid.hashCode());
1535f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root            return hash;
1545f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root        }
15516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    }
15616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static {
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        classInitNative();
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
161bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    public BluetoothService(Context context) {
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext = context;
163105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
164105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Need to do this in place of:
165105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // mBatteryStats = BatteryStatsService.getService();
166105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Since we can not import BatteryStatsService from here. This class really needs to be
167105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // moved to java/services/com/android/server/
168105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo"));
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        initializeNativeDataNative();
171ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project
172ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project        if (isEnabledNative() == 1) {
173ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project            Log.w(TAG, "Bluetooth daemons already running - runtime restart? ");
174ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project            disableNative();
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
176ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project
177de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        mBluetoothState = BluetoothAdapter.STATE_OFF;
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mIsDiscovering = false;
179bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mAdapterProperties = new HashMap<String, String>();
180bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mDeviceProperties = new HashMap<String, Map<String,String>>();
18110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
18210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        mDeviceServiceChannelCache = new HashMap<String, Map<ParcelUuid, Integer>>();
1831caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        mUuidIntentTracker = new ArrayList<String>();
18416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        mUuidCallbackTracker = new HashMap<RemoteService, IBluetoothCallback>();
18524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        mServiceRecordToPid = new HashMap<Integer, Integer>();
1869b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        mProfileConnectionMgr = new HashMap<String, BluetoothProfileConnectionState>();
1873fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
1883fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        IntentFilter filter = new IntentFilter();
1896e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh        registerForAirplaneMode(filter);
1906e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh
1913fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        filter.addAction(Intent.ACTION_DOCK_EVENT);
1926e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh        mContext.registerReceiver(mReceiver, filter);
1933fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    }
1943fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
1959b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public static synchronized String readDockBluetoothAddress() {
1963fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        if (mDockAddress != null) return mDockAddress;
1973fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
1983fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        BufferedInputStream file = null;
1993fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        String dockAddress;
2003fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        try {
2013fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            file = new BufferedInputStream(new FileInputStream(DOCK_ADDRESS_PATH));
2023fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            byte[] address = new byte[17];
2033fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            file.read(address);
2043fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            dockAddress = new String(address);
2053fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            dockAddress = dockAddress.toUpperCase();
2063fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            if (BluetoothAdapter.checkBluetoothAddress(dockAddress)) {
2073fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                mDockAddress = dockAddress;
2083fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                return mDockAddress;
2093fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            } else {
2103fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                log("CheckBluetoothAddress failed for car dock address:" + dockAddress);
2113fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            }
2123fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        } catch (FileNotFoundException e) {
2133fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            log("FileNotFoundException while trying to read dock address");
2143fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        } catch (IOException e) {
2153fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            log("IOException while trying to read dock address");
2163fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        } finally {
2173fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            if (file != null) {
2183fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                try {
2193fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                    file.close();
2203fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                } catch (IOException e) {
2213fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                    // Ignore
2223fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                }
2233fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            }
2243fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        }
2253fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        mDockAddress = null;
2263fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        return null;
2273fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    }
2283fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
2293fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    private synchronized boolean writeDockPin() {
2303fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        BufferedWriter out = null;
2313fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        try {
2323fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            out = new BufferedWriter(new FileWriter(DOCK_PIN_PATH));
2333fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
2343fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            // Generate a random 4 digit pin between 0000 and 9999
2353fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            // This is not truly random but good enough for our purposes.
2363fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            int pin = (int) Math.floor(Math.random() * 10000);
2373fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
2383fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            mDockPin = String.format("%04d", pin);
2393fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            out.write(mDockPin);
2403fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            return true;
2413fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        } catch (FileNotFoundException e) {
2423fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            log("FileNotFoundException while trying to write dock pairing pin");
2433fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        } catch (IOException e) {
2443fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            log("IOException while while trying to write dock pairing pin");
2453fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        } finally {
2463fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            if (out != null) {
2473fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                try {
2483fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                    out.close();
2493fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                } catch (IOException e) {
2503fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                    // Ignore
2513fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                }
2523fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            }
2533fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        }
2543fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        mDockPin = null;
2553fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        return false;
2563fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    }
2573fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
2583fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    /*package*/ synchronized String getDockPin() {
2593fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        return mDockPin;
260bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    }
261bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly
262bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    public synchronized void initAfterRegistration() {
263f242b7b931898856bcbcb7ec36cacf43098ba544Nick Pelly        mAdapter = BluetoothAdapter.getDefaultAdapter();
264bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mEventLoop = new BluetoothEventLoop(mContext, mAdapter, this);
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void finalize() throws Throwable {
2696e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh        mContext.unregisterReceiver(mReceiver);
2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            cleanupNativeDataNative();
2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super.finalize();
2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean isEnabled() {
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
2798c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        return isEnabledInternal();
2808c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh    }
2818c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
2828c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh    private boolean isEnabledInternal() {
283de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        return mBluetoothState == BluetoothAdapter.STATE_ON;
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
286105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    public int getBluetoothState() {
287105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
288105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        return mBluetoothState;
289105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    }
290105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
291105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Bring down bluetooth and disable BT in settings. Returns true on success.
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean disable() {
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return disable(true);
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Bring down bluetooth. Returns true on success.
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
302e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly     * @param saveSetting If true, persist the new setting
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean disable(boolean saveSetting) {
305e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission");
3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
307105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        switch (mBluetoothState) {
308de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_OFF:
309105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return true;
310de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_ON:
311105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            break;
312105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        default:
313105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return false;
314105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mEnableThread != null && mEnableThread.isAlive()) {
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
318de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        setBluetoothState(BluetoothAdapter.STATE_TURNING_OFF);
319bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly        mHandler.removeMessages(MESSAGE_REGISTER_SDP_RECORDS);
320105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
321105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Allow 3 seconds for profiles to gracefully disconnect
322105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // TODO: Introduce a callback mechanism so that each profile can notify
323bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        // BluetoothService when it is done shutting down
324105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mHandler.sendMessageDelayed(
325105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                mHandler.obtainMessage(MESSAGE_FINISH_DISABLE, saveSetting ? 1 : 0, 0), 3000);
326105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        return true;
327105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    }
328105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
329105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
330105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private synchronized void finishDisable(boolean saveSetting) {
331de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        if (mBluetoothState != BluetoothAdapter.STATE_TURNING_OFF) {
332105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return;
3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mEventLoop.stop();
335d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        tearDownNativeDataNative();
3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        disableNative();
3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // mark in progress bondings as cancelled
3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (String address : mBondState.listInState(BluetoothDevice.BOND_BONDING)) {
340005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            mBondState.setBondState(address, BluetoothDevice.BOND_NONE,
3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // update mode
345de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        Intent intent = new Intent(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
346de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        intent.putExtra(BluetoothAdapter.EXTRA_SCAN_MODE, BluetoothAdapter.SCAN_MODE_NONE);
3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.sendBroadcast(intent, BLUETOOTH_PERM);
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
349105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mIsDiscovering = false;
350bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mAdapterProperties.clear();
35124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        mServiceRecordToPid.clear();
352105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (saveSetting) {
3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            persistBluetoothOnSetting(false);
3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
356105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
357de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        setBluetoothState(BluetoothAdapter.STATE_OFF);
358105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
359105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Log bluetooth off to battery stats.
360105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        long ident = Binder.clearCallingIdentity();
361105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        try {
362105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            mBatteryStats.noteBluetoothOff();
363105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        } catch (RemoteException e) {
364105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        } finally {
365105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            Binder.restoreCallingIdentity(ident);
366105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
367997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly
368997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        if (mRestart) {
369997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly            mRestart = false;
370997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly            enable();
371997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        }
3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
374105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    /** Bring up BT and persist BT on in settings */
375105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    public boolean enable() {
376105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        return enable(true);
3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Enable this Bluetooth device, asynchronously.
3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * This turns on/off the underlying hardware.
3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
383105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project     * @param saveSetting If true, persist the new state of BT in settings
384105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project     * @return True on success (so far)
3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
386105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    public synchronized boolean enable(boolean saveSetting) {
3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Airplane mode can prevent Bluetooth radio from being turned on.
39144303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        if (mIsAirplaneSensitive && isAirplaneModeOn() && !mIsAirplaneToggleable) {
3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
394de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        if (mBluetoothState != BluetoothAdapter.STATE_OFF) {
3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mEnableThread != null && mEnableThread.isAlive()) {
3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
400de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        setBluetoothState(BluetoothAdapter.STATE_TURNING_ON);
401105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mEnableThread = new EnableThread(saveSetting);
4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mEnableThread.start();
4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
406997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly    /** Forcibly restart Bluetooth if it is on */
407997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly    /* package */ synchronized void restart() {
408de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        if (mBluetoothState != BluetoothAdapter.STATE_ON) {
409997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly            return;
410997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        }
411997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        mRestart = true;
412997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        if (!disable(false)) {
413997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly            mRestart = false;
414997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        }
415d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
416997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly
417105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private synchronized void setBluetoothState(int state) {
418105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        if (state == mBluetoothState) {
419105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return;
420105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
421105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
422105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        if (DBG) log("Bluetooth state " + mBluetoothState + " -> " + state);
423105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
424de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
425de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, mBluetoothState);
426de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        intent.putExtra(BluetoothAdapter.EXTRA_STATE, state);
427105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
428105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
429105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mBluetoothState = state;
430105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
431105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mContext.sendBroadcast(intent, BLUETOOTH_PERM);
432105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    }
433105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final Handler mHandler = new Handler() {
4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void handleMessage(Message msg) {
4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            switch (msg.what) {
438105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            case MESSAGE_REGISTER_SDP_RECORDS:
4398c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh                if (!isEnabledInternal()) {
440bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    return;
441bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                }
442bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                // SystemService.start() forks sdptool to register service
443bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                // records. It can fail to register some records if it is
444bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                // forked multiple times in a row, probably because there is
445bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                // some race in sdptool or bluez when operated in parallel.
446bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                // As a workaround, delay 500ms between each fork of sdptool.
447bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                // TODO: Don't fork sdptool in order to regsiter service
448bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                // records, use a DBUS call instead.
449bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                switch (msg.arg1) {
450bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                case 1:
45177b4ad0e496941a28382eb938a05831f1f8d2d4aJaikumar Ganesh                    Log.d(TAG, "Registering hfag record");
45277b4ad0e496941a28382eb938a05831f1f8d2d4aJaikumar Ganesh                    SystemService.start("hfag");
453bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    mHandler.sendMessageDelayed(
454bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                            mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS, 2, -1), 500);
455bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    break;
456bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                case 2:
45777b4ad0e496941a28382eb938a05831f1f8d2d4aJaikumar Ganesh                    Log.d(TAG, "Registering hsag record");
45877b4ad0e496941a28382eb938a05831f1f8d2d4aJaikumar Ganesh                    SystemService.start("hsag");
459bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    mHandler.sendMessageDelayed(
460bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                            mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS, 3, -1), 500);
461bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    break;
462bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                case 3:
463bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    Log.d(TAG, "Registering opush record");
46403c707ab6fc97e99b1603b8d6edc604dbea3cd6fNick Pelly                    SystemService.start("opush");
465bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    mHandler.sendMessageDelayed(
466bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                            mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS, 4, -1), 500);
467bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    break;
468bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                case 4:
469bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    Log.d(TAG, "Registering pbap record");
47067542964876aa7e4216e8f69f21dda68e7463b9aJaikumar Ganesh                    SystemService.start("pbap");
471bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    break;
4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
473105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                break;
474105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            case MESSAGE_FINISH_DISABLE:
475105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                finishDisable(msg.arg1 != 0);
476105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                break;
4771caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            case MESSAGE_UUID_INTENT:
4781caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh                String address = (String)msg.obj;
47916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (address != null) {
4801caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh                    sendUuidIntent(address);
48116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    makeServiceChannelCallbacks(address);
48216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                }
4831caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh                break;
48412835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            case MESSAGE_DISCOVERABLE_TIMEOUT:
48512835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                int mode = msg.arg1;
4868c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh                if (isEnabledInternal()) {
48712835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                    // TODO: Switch back to the previous scan mode
48812835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                    // This is ok for now, because we only use
48912835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                    // CONNECTABLE and CONNECTABLE_DISCOVERABLE
49012835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                    setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE, -1);
49112835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                }
49212835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                break;
4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private EnableThread mEnableThread;
4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private class EnableThread extends Thread {
5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final boolean mSaveSetting;
501105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        public EnableThread(boolean saveSetting) {
5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mSaveSetting = saveSetting;
5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void run() {
5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean res = (enableNative() == 0);
5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (res) {
507b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                int retryCount = 2;
508b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                boolean running = false;
509b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                while ((retryCount-- > 0) && !running) {
510b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    mEventLoop.start();
511105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    // it may take a momement for the other thread to do its
512b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    // thing.  Check periodically for a while.
513b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    int pollCount = 5;
514b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    while ((pollCount-- > 0) && !running) {
515b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                        if (mEventLoop.isEventLoopRunning()) {
516b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                            running = true;
517b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                            break;
518b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                        }
519b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                        try {
520b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                            Thread.sleep(100);
521b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                        } catch (InterruptedException e) {}
522b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    }
523b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                }
524b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                if (!running) {
525b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    log("bt EnableThread giving up");
526b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    res = false;
527b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    disableNative();
528b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                }
5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (res) {
533d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                if (!setupNativeDataNative()) {
534d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                    return;
535d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                }
5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mSaveSetting) {
5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    persistBluetoothOnSetting(true);
5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mIsDiscovering = false;
540c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                mBondState.readAutoPairingData();
5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mBondState.loadBondState();
5429b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                initProfileState();
543bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                mHandler.sendMessageDelayed(
544bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                        mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS, 1, -1), 3000);
5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
546105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                // Log bluetooth on to battery stats.
547105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                long ident = Binder.clearCallingIdentity();
548105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                try {
549105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    mBatteryStats.noteBluetoothOn();
550105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                } catch (RemoteException e) {
551105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                } finally {
552105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    Binder.restoreCallingIdentity(ident);
553105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                }
5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
555105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
556105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            mEnableThread = null;
557105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
558105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            setBluetoothState(res ?
559de893f550301a60274e87aa8168225e7a7a42184Nick Pelly                              BluetoothAdapter.STATE_ON :
560de893f550301a60274e87aa8168225e7a7a42184Nick Pelly                              BluetoothAdapter.STATE_OFF);
561105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
562b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            if (res) {
563105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                // Update mode
564d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                String[] propVal = {"Pairable", getProperty("Pairable")};
565d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                mEventLoop.onPropertyChanged(propVal);
566b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            }
567b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project
56844303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey            if (mIsAirplaneSensitive && isAirplaneModeOn() && !mIsAirplaneToggleable) {
5695c43f735d94a538dc273c8f859d1100a7cdd5c71Daisuke Miyakawa                disable(false);
5705c43f735d94a538dc273c8f859d1100a7cdd5c71Daisuke Miyakawa            }
5715c43f735d94a538dc273c8f859d1100a7cdd5c71Daisuke Miyakawa
5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void persistBluetoothOnSetting(boolean bluetoothOn) {
5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long origCallerIdentityToken = Binder.clearCallingIdentity();
5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.BLUETOOTH_ON,
5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                bluetoothOn ? 1 : 0);
5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Binder.restoreCallingIdentity(origCallerIdentityToken);
5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* package */ BondState getBondState() {
5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mBondState;
5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** local cache of bonding state.
5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* we keep our own state to track the intermediate state BONDING, which
5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* bluez does not track.
5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * All addreses must be passed in upper case.
5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public class BondState {
5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final HashMap<String, Integer> mState = new HashMap<String, Integer>();
5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final HashMap<String, Integer> mPinAttempt = new HashMap<String, Integer>();
594c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh
595c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        private static final String AUTO_PAIRING_BLACKLIST =
596c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            "/etc/bluetooth/auto_pairing.conf";
597c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        private static final String DYNAMIC_AUTO_PAIRING_BLACKLIST =
598c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            "/data/misc/bluetooth/dynamic_auto_pairing.conf";
599c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        private ArrayList<String>  mAutoPairingAddressBlacklist;
600c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        private ArrayList<String> mAutoPairingExactNameBlacklist;
601c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        private ArrayList<String> mAutoPairingPartialNameBlacklist;
602c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        // Addresses added to blacklist dynamically based on usage.
603c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        private ArrayList<String> mAutoPairingDynamicAddressBlacklist;
604c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh
605482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh
6062092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        // If this is an outgoing connection, store the address.
6072092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        // There can be only 1 pending outgoing connection at a time,
6082092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        private String mPendingOutgoingBonding;
6092092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
6102092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        private synchronized void setPendingOutgoingBonding(String address) {
6112092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh            mPendingOutgoingBonding = address;
6122092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        }
6132092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
6142092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        public synchronized String getPendingOutgoingBonding() {
6152092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh            return mPendingOutgoingBonding;
6162092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        }
6172092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
6189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized void loadBondState() {
619de893f550301a60274e87aa8168225e7a7a42184Nick Pelly            if (mBluetoothState != BluetoothAdapter.STATE_TURNING_ON) {
6209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
622d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            String []bonds = null;
623b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh            String val = getPropertyInternal("Devices");
624d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            if (val != null) {
625d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                bonds = val.split(",");
626d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            }
6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (bonds == null) {
6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mState.clear();
6319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (DBG) log("found " + bonds.length + " bonded devices");
632d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            for (String device : bonds) {
633d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                mState.put(getAddressFromObjectPath(device).toUpperCase(),
634d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                        BluetoothDevice.BOND_BONDED);
6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized void setBondState(String address, int state) {
6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setBondState(address, state, 0);
6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /** reason is ignored unless state == BOND_NOT_BONDED */
6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized void setBondState(String address, int state, int reason) {
6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int oldState = getBondState(address);
6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (oldState == state) {
6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6482092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
6492092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh            // Check if this was an pending outgoing bonding.
6502092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh            // If yes, reset the state.
6512092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh            if (oldState == BluetoothDevice.BOND_BONDING) {
6522092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh                if (address.equals(mPendingOutgoingBonding)) {
6532092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh                    mPendingOutgoingBonding = null;
6542092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh                }
6552092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh            }
6562092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
6579b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            if (state == BluetoothDevice.BOND_BONDED) {
6589b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                addProfileState(address);
6599b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            } else if (state == BluetoothDevice.BOND_NONE) {
6609b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                removeProfileState(address);
6619b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            }
6629b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (DBG) log(address + " bond state " + oldState + " -> " + state + " (" +
6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                         reason + ")");
665005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            Intent intent = new Intent(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
666005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
667005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            intent.putExtra(BluetoothDevice.EXTRA_BOND_STATE, state);
668005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            intent.putExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, oldState);
669005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            if (state == BluetoothDevice.BOND_NONE) {
6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (reason <= 0) {
6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Log.w(TAG, "setBondState() called to unbond device, but reason code is " +
6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                          "invalid. Overriding reason code with BOND_RESULT_REMOVED");
6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    reason = BluetoothDevice.UNBOND_REASON_REMOVED;
6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
675005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly                intent.putExtra(BluetoothDevice.EXTRA_REASON, reason);
6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mState.remove(address);
6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mState.put(address, state);
6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mContext.sendBroadcast(intent, BLUETOOTH_PERM);
6829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public boolean isAutoPairingBlacklisted(String address) {
685c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            if (mAutoPairingAddressBlacklist != null) {
686c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                for (String blacklistAddress : mAutoPairingAddressBlacklist) {
687c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    if (address.startsWith(blacklistAddress)) return true;
688c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                }
6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
690482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh
691c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            if (mAutoPairingDynamicAddressBlacklist != null) {
692c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                for (String blacklistAddress: mAutoPairingDynamicAddressBlacklist) {
693c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    if (address.equals(blacklistAddress)) return true;
694c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                }
695c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            }
696482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh            String name = getRemoteName(address);
697482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh            if (name != null) {
698c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                if (mAutoPairingExactNameBlacklist != null) {
699c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    for (String blacklistName : mAutoPairingExactNameBlacklist) {
700c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        if (name.equals(blacklistName)) return true;
701c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    }
702738ed80262aa26128924c51f59ffd49e1163eb8dJaikumar Ganesh                }
703738ed80262aa26128924c51f59ffd49e1163eb8dJaikumar Ganesh
704c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                if (mAutoPairingPartialNameBlacklist != null) {
705c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    for (String blacklistName : mAutoPairingPartialNameBlacklist) {
706c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        if (name.startsWith(blacklistName)) return true;
707c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    }
708482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh                }
709482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh            }
7109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized int getBondState(String address) {
7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Integer state = mState.get(address);
7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (state == null) {
716005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly                return BluetoothDevice.BOND_NONE;
7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return state.intValue();
7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
721e5d93b7ed983f98855555d560faf060836f1a52fJaikumar Ganesh        /*package*/ synchronized String[] listInState(int state) {
7229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ArrayList<String> result = new ArrayList<String>(mState.size());
7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (Map.Entry<String, Integer> e : mState.entrySet()) {
7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (e.getValue().intValue() == state) {
7259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    result.add(e.getKey());
7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return result.toArray(new String[result.size()]);
7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized void addAutoPairingFailure(String address) {
732c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            if (mAutoPairingDynamicAddressBlacklist == null) {
733c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                mAutoPairingDynamicAddressBlacklist = new ArrayList<String>();
7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
735c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh
736c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            updateAutoPairingData(address);
737c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            mAutoPairingDynamicAddressBlacklist.add(address);
7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized boolean isAutoPairingAttemptsInProgress(String address) {
7419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return getAttempt(address) != 0;
7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized void clearPinAttempts(String address) {
7459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mPinAttempt.remove(address);
7469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized boolean hasAutoPairingFailed(String address) {
749c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            if (mAutoPairingDynamicAddressBlacklist == null) return false;
750c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh
751c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            return mAutoPairingDynamicAddressBlacklist.contains(address);
7529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized int getAttempt(String address) {
7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Integer attempt = mPinAttempt.get(address);
7569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (attempt == null) {
7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return 0;
7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return attempt.intValue();
7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized void attempt(String address) {
7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Integer attempt = mPinAttempt.get(address);
7649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int newAttempt;
7659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (attempt == null) {
7669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                newAttempt = 1;
7679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
7689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                newAttempt = attempt.intValue() + 1;
7699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mPinAttempt.put(address, new Integer(newAttempt));
7719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
773c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        private void copyAutoPairingData() {
774c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            File file = null;
775c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            FileInputStream in = null;
776c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            FileOutputStream out = null;
777c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            try {
778c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                file = new File(DYNAMIC_AUTO_PAIRING_BLACKLIST);
779c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                if (file.exists()) return;
780c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh
781c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                in = new FileInputStream(AUTO_PAIRING_BLACKLIST);
782c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                out= new FileOutputStream(DYNAMIC_AUTO_PAIRING_BLACKLIST);
783c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh
784c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                byte[] buf = new byte[1024];
785c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                int len;
786c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                while ((len = in.read(buf)) > 0) {
787c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    out.write(buf, 0, len);
788c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                }
789c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            } catch (FileNotFoundException e) {
790c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                log("FileNotFoundException: in copyAutoPairingData");
791c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            } catch (IOException e) {
792c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                log("IOException: in copyAutoPairingData");
793c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            } finally {
794c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                 try {
795c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                     if (in != null) in.close();
796c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                     if (out != null) out.close();
797c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                 } catch (IOException e) {}
798c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            }
799c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        }
800c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh
801c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        public void readAutoPairingData() {
802c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            if (mAutoPairingAddressBlacklist != null) return;
803c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            copyAutoPairingData();
804c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            FileInputStream fstream = null;
805c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            try {
806c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                fstream = new FileInputStream(DYNAMIC_AUTO_PAIRING_BLACKLIST);
807c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                DataInputStream in = new DataInputStream(fstream);
808c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                BufferedReader file = new BufferedReader(new InputStreamReader(in));
809c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                String line;
810c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                while((line = file.readLine()) != null) {
811c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    line = line.trim();
812c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    if (line.length() == 0 || line.startsWith("//")) continue;
813c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    String[] value = line.split("=");
814c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    if (value != null && value.length == 2) {
815c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        String[] val = value[1].split(",");
816c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        if (value[0].equalsIgnoreCase("AddressBlacklist")) {
817c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                            mAutoPairingAddressBlacklist =
818c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                                new ArrayList<String>(Arrays.asList(val));
819c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        } else if (value[0].equalsIgnoreCase("ExactNameBlacklist")) {
820c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                            mAutoPairingExactNameBlacklist =
821c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                                new ArrayList<String>(Arrays.asList(val));
822c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        } else if (value[0].equalsIgnoreCase("PartialNameBlacklist")) {
823c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                            mAutoPairingPartialNameBlacklist =
824c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                                new ArrayList<String>(Arrays.asList(val));
825c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        } else if (value[0].equalsIgnoreCase("DynamicAddressBlacklist")) {
826c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                            mAutoPairingDynamicAddressBlacklist =
827c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                                new ArrayList<String>(Arrays.asList(val));
828c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        } else {
829c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                            Log.e(TAG, "Error parsing Auto pairing blacklist file");
830c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        }
831c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    }
832c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                }
833c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            } catch (FileNotFoundException e) {
834c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                log("FileNotFoundException: readAutoPairingData" + e.toString());
835c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            } catch (IOException e) {
836c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                log("IOException: readAutoPairingData" + e.toString());
837c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            } finally {
838c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                if (fstream != null) {
839c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    try {
840c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        fstream.close();
841c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    } catch (IOException e) {
842c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        // Ignore
843c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    }
844c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                }
845c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            }
846c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        }
847c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh
848c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        // This function adds a bluetooth address to the auto pairing blacklis
849c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        // file. These addresses are added to DynamicAddressBlacklistSection
850c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        private void updateAutoPairingData(String address) {
851c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            BufferedWriter out = null;
852c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            try {
853c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                out = new BufferedWriter(new FileWriter(DYNAMIC_AUTO_PAIRING_BLACKLIST, true));
854c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                StringBuilder str = new StringBuilder();
855c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                if (mAutoPairingDynamicAddressBlacklist.size() == 0) {
856c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    str.append("DynamicAddressBlacklist=");
857c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                }
858c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                str.append(address);
859c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                str.append(",");
860c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                out.write(str.toString());
861c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            } catch (FileNotFoundException e) {
862c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                log("FileNotFoundException: updateAutoPairingData" + e.toString());
863c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            } catch (IOException e) {
864c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                log("IOException: updateAutoPairingData" + e.toString());
865c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            } finally {
866c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                if (out != null) {
867c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    try {
868c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        out.close();
869c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    } catch (IOException e) {
870c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        // Ignore
871c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    }
872c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                }
873c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            }
874c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        }
8759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static String toBondStateString(int bondState) {
8789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        switch (bondState) {
879005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        case BluetoothDevice.BOND_NONE:
8809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "not bonded";
8819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case BluetoothDevice.BOND_BONDING:
8829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "bonding";
8839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case BluetoothDevice.BOND_BONDED:
8849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "bonded";
8859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        default:
8869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "??????";
8879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8909519ce75f15ba287a641166c1b7ed10f2aa73f74Jaikumar Ganesh    /*package*/ synchronized boolean isAdapterPropertiesEmpty() {
8919519ce75f15ba287a641166c1b7ed10f2aa73f74Jaikumar Ganesh        return mAdapterProperties.isEmpty();
8929519ce75f15ba287a641166c1b7ed10f2aa73f74Jaikumar Ganesh    }
8939519ce75f15ba287a641166c1b7ed10f2aa73f74Jaikumar Ganesh
894d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /*package*/synchronized void getAllProperties() {
8958c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
8969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
897bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mAdapterProperties.clear();
898d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
899d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String properties[] = (String [])getAdapterPropertiesNative();
900d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        // The String Array consists of key-value pairs.
901d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (properties == null) {
902d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            Log.e(TAG, "*Error*: GetAdapterProperties returned NULL");
903d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return;
904d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
905d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
9068bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh        for (int i = 0; i < properties.length; i++) {
9078bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            String name = properties[i];
908efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh            String newValue = null;
9098bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            int len;
9108bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            if (name == null) {
9118bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                Log.e(TAG, "Error:Adapter Property at index" + i + "is null");
9128bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                continue;
9138bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            }
9148bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            if (name.equals("Devices")) {
915efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                StringBuilder str = new StringBuilder();
9168bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                len = Integer.valueOf(properties[++i]);
9178bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                for (int j = 0; j < len; j++) {
918efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                    str.append(properties[++i]);
919efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                    str.append(",");
920efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                }
921efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                if (len > 0) {
922efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                    newValue = str.toString();
9238bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                }
9248bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            } else {
9258bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                newValue = properties[++i];
9268bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            }
927bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            mAdapterProperties.put(name, newValue);
928d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
929d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
930d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        // Add adapter object path property.
931d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String adapterPath = getAdapterPathNative();
932d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (adapterPath != null)
933bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            mAdapterProperties.put("ObjectPath", adapterPath + "/dev_");
9349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
936d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ synchronized void setProperty(String name, String value) {
937bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mAdapterProperties.put(name, value);
9389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean setName(String name) {
9419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
9429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
9439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (name == null) {
9449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
9459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
946d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setPropertyString("Name", name);
9479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
949d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    //TODO(): setPropertyString, setPropertyInteger, setPropertyBoolean
950d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    // Either have a single property function with Object as the parameter
951d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    // or have a function for each property and then obfuscate in the JNI layer.
952d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    // The following looks dirty.
953d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private boolean setPropertyString(String key, String value) {
9549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
9558c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
956d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setAdapterPropertyStringNative(key, value);
9579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
959d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private boolean setPropertyInteger(String key, int value) {
960d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
9618c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
962d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setAdapterPropertyIntegerNative(key, value);
963d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
9649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
965d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private boolean setPropertyBoolean(String key, boolean value) {
966d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
9678c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
968d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setAdapterPropertyBooleanNative(key, value ? 1 : 0);
9699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
971d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /**
972d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Set the discoverability window for the device.  A timeout of zero
973d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * makes the device permanently discoverable (if the device is
974d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * discoverable).  Setting the timeout to a nonzero value does not make
975d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * a device discoverable; you need to call setMode() to make the device
976d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * explicitly discoverable.
977d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     *
978d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * @param timeout_s The discoverable timeout in seconds.
979d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     */
980d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized boolean setDiscoverableTimeout(int timeout) {
9819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
9829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
983d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setPropertyInteger("DiscoverableTimeout", timeout);
9849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
98612835478ee687a493d1b5882e67b6725bd539c26Nick Pelly    public synchronized boolean setScanMode(int mode, int duration) {
98718b1e79a123b979d25bfa5d0b0ee5d0382dbd64bNick Pelly        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS,
98818b1e79a123b979d25bfa5d0b0ee5d0382dbd64bNick Pelly                                                "Need WRITE_SECURE_SETTINGS permission");
989de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        boolean pairable = false;
990de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        boolean discoverable = false;
99112835478ee687a493d1b5882e67b6725bd539c26Nick Pelly
992de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        switch (mode) {
993de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.SCAN_MODE_NONE:
99412835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            mHandler.removeMessages(MESSAGE_DISCOVERABLE_TIMEOUT);
995d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            pairable = false;
996d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            discoverable = false;
997de893f550301a60274e87aa8168225e7a7a42184Nick Pelly            break;
998de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
99912835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            mHandler.removeMessages(MESSAGE_DISCOVERABLE_TIMEOUT);
1000d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            pairable = true;
1001d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            discoverable = false;
1002005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            break;
1003de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
100412835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            mHandler.removeMessages(MESSAGE_DISCOVERABLE_TIMEOUT);
1005d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            pairable = true;
1006d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            discoverable = true;
100712835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            Message msg = mHandler.obtainMessage(MESSAGE_DISCOVERABLE_TIMEOUT);
100812835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            mHandler.sendMessageDelayed(msg, duration * 1000);
100912835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            if (DBG) Log.d(TAG, "BT Discoverable for " + duration + " seconds");
1010005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            break;
1011de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        default:
1012de893f550301a60274e87aa8168225e7a7a42184Nick Pelly            Log.w(TAG, "Requested invalid scan mode " + mode);
1013de893f550301a60274e87aa8168225e7a7a42184Nick Pelly            return false;
1014d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
1015d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        setPropertyBoolean("Pairable", pairable);
1016d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        setPropertyBoolean("Discoverable", discoverable);
10179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1018d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return true;
10199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1021b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh    /*package*/ synchronized String getProperty(String name) {
1022b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh        if (!isEnabledInternal()) return null;
1023b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh        return getPropertyInternal(name);
1024b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh    }
1025b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh
1026b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh    /*package*/ synchronized String getPropertyInternal(String name) {
1027bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        if (!mAdapterProperties.isEmpty())
1028bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            return mAdapterProperties.get(name);
1029d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        getAllProperties();
1030bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        return mAdapterProperties.get(name);
10319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1033d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized String getAddress() {
1034d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1035d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return getProperty("Address");
10369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1038d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized String getName() {
10399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1040d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return getProperty("Name");
10419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1044d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Returns the user-friendly name of a remote device.  This value is
1045d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * returned from our local cache, which is updated when onPropertyChange
1046d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * event is received.
1047d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Do not expect to retrieve the updated remote name immediately after
1048d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * changing the name on the remote device.
10499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1050d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * @param address Bluetooth address of remote device.
1051d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     *
1052d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * @return The user-friendly name of the specified remote device.
10539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1054d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized String getRemoteName(String address) {
1055d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1056005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1057d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return null;
1058d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
105955929a958bf0e482c8e4d7df3dd75957f1e9d871Jaikumar Ganesh        return getRemoteDeviceProperty(address, "Name");
10609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
10639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Get the discoverability window for the device.  A timeout of zero
10649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * means that the device is permanently discoverable (if the device is
10659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * in the discoverable mode).
10669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
10679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The discoverability window of the device, in seconds.  A negative
10689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         value indicates an error.
10699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
10709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized int getDiscoverableTimeout() {
10719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1072d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String timeout = getProperty("DiscoverableTimeout");
1073d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (timeout != null)
1074d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh           return Integer.valueOf(timeout);
1075d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        else
1076d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return -1;
10779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized int getScanMode() {
10809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
10818c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal())
1082de893f550301a60274e87aa8168225e7a7a42184Nick Pelly            return BluetoothAdapter.SCAN_MODE_NONE;
1083d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1084d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        boolean pairable = getProperty("Pairable").equals("true");
1085d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        boolean discoverable = getProperty("Discoverable").equals("true");
1086d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return bluezStringToScanMode (pairable, discoverable);
10879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1089d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized boolean startDiscovery() {
10909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
10919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
10928c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
10938c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1094d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return startDiscoveryNative();
10959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1097d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized boolean cancelDiscovery() {
10989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
10999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
11008c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
11018c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1102d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return stopDiscoveryNative();
1103d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
1104d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1105d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized boolean isDiscovering() {
1106d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1107d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return mIsDiscovering;
1108d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
1109d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1110d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ void setIsDiscovering(boolean isDiscovering) {
1111d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mIsDiscovering = isDiscovering;
11129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean createBond(String address) {
11159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
11169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
11178c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
11188c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1119005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
11209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
11219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        address = address.toUpperCase();
11239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11242092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        if (mBondState.getPendingOutgoingBonding() != null) {
11259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            log("Ignoring createBond(): another device is bonding");
11269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // a different device is currently bonding, fail
11279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
11289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Check for bond state only if we are not performing auto
11319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // pairing exponential back-off attempts.
11329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mBondState.isAutoPairingAttemptsInProgress(address) &&
1133005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly                mBondState.getBondState(address) != BluetoothDevice.BOND_NONE) {
11349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            log("Ignoring createBond(): this device is already bonding or bonded");
11359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
11369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11383fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        if (address.equals(mDockAddress)) {
11393fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            if (!writeDockPin()) {
11403fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                log("Error while writing Pin for the dock");
11413fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                return false;
11423fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            }
11433fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        }
11443fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
1145d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (!createPairedDeviceNative(address, 60000 /* 1 minute */)) {
11469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
11479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11492092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        mBondState.setPendingOutgoingBonding(address);
11509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mBondState.setBondState(address, BluetoothDevice.BOND_BONDING);
11512092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
11529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
11539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean cancelBondProcess(String address) {
11569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
11579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
11588c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
11598c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1160005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
11619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
11629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        address = address.toUpperCase();
11649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mBondState.getBondState(address) != BluetoothDevice.BOND_BONDING) {
11659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
11669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1168005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        mBondState.setBondState(address, BluetoothDevice.BOND_NONE,
11699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
1170d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        cancelDeviceCreationNative(address);
11719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
11729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean removeBond(String address) {
11759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
11769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
11778c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
11788c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1179005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
11809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
11819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11829b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        BluetoothProfileConnectionState state = mProfileConnectionMgr.get(address);
11839b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (state != null) {
11849b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            state.sendMessage(BluetoothProfileConnectionState.UNPAIR);
11859b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            return true;
11869b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        } else {
11879b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            return false;
11889b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
11899b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
11909b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
11919b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public synchronized boolean removeBondInternal(String address) {
1192d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return removeDeviceNative(getObjectPathFromAddress(address));
11939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized String[] listBonds() {
11969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
11979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mBondState.listInState(BluetoothDevice.BOND_BONDED);
11989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized int getBondState(String address) {
12019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1202005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1203b24e11baac589fe16426f2d243b460ab84991c7bNick Pelly            return BluetoothDevice.ERROR;
12049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mBondState.getBondState(address.toUpperCase());
12069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12083fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    public synchronized boolean isBluetoothDock(String address) {
12096e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh        SharedPreferences sp = mContext.getSharedPreferences(SHARED_PREFERENCES_NAME,
12106e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                mContext.MODE_PRIVATE);
12116e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh
12126e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh        return sp.contains(SHARED_PREFERENCE_DOCK_ADDRESS + address);
12133fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    }
12143fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
12159488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh    /*package*/ boolean isRemoteDeviceInCache(String address) {
1216bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        return (mDeviceProperties.get(address) != null);
12179488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh    }
12189488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh
12199488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh    /*package*/ String[] getRemoteDeviceProperties(String address) {
12208c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return null;
12218c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
12229488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh        String objectPath = getObjectPathFromAddress(address);
12239488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh        return (String [])getDevicePropertiesNative(objectPath);
12249488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh    }
12259488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh
1226d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /*package*/ synchronized String getRemoteDeviceProperty(String address, String property) {
1227bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        Map<String, String> properties = mDeviceProperties.get(address);
1228d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (properties != null) {
1229d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return properties.get(property);
1230d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        } else {
1231d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            // Query for remote device properties, again.
1232d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            // We will need to reload the cache when we switch Bluetooth on / off
1233d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            // or if we crash.
123410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            if (updateRemoteDevicePropertiesCache(address))
1235d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                return getRemoteDeviceProperty(address, property);
12369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1237d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        Log.e(TAG, "getRemoteDeviceProperty: " + property + "not present:" + address);
1238d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return null;
12399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
124110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh    /* package */ synchronized boolean updateRemoteDevicePropertiesCache(String address) {
124210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        String[] propValues = getRemoteDeviceProperties(address);
124310eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        if (propValues != null) {
124410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            addRemoteDeviceProperties(address, propValues);
124510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            return true;
124610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        }
124710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        return false;
124810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh    }
124910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
1250d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ synchronized void addRemoteDeviceProperties(String address, String[] properties) {
1251395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh        /*
1252395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh         * We get a DeviceFound signal every time RSSI changes or name changes.
1253395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh         * Don't create a new Map object every time */
1254bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        Map<String, String> propertyValues = mDeviceProperties.get(address);
1255efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh        if (propertyValues == null) {
1256395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh            propertyValues = new HashMap<String, String>();
1257395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh        }
1258395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh
12598bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh        for (int i = 0; i < properties.length; i++) {
12608bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            String name = properties[i];
1261efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh            String newValue = null;
12628bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            int len;
12638bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            if (name == null) {
12648bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                Log.e(TAG, "Error: Remote Device Property at index" + i + "is null");
12658bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                continue;
12668bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            }
12678bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            if (name.equals("UUIDs") || name.equals("Nodes")) {
1268efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                StringBuilder str = new StringBuilder();
12698bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                len = Integer.valueOf(properties[++i]);
12708bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                for (int j = 0; j < len; j++) {
1271efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                    str.append(properties[++i]);
1272efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                    str.append(",");
1273efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                }
1274efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                if (len > 0) {
1275efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                    newValue = str.toString();
12768bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                }
1277d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            } else {
12788bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                newValue = properties[++i];
1279d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            }
1280efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh
12818bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            propertyValues.put(name, newValue);
12829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1283bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mDeviceProperties.put(address, propertyValues);
128410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
128510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        // We have added a new remote device or updated its properties.
128610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        // Also update the serviceChannel cache.
128710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        updateDeviceServiceChannelCache(address);
12889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1290d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ void removeRemoteDeviceProperties(String address) {
1291bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mDeviceProperties.remove(address);
12929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1294d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ synchronized void setRemoteDeviceProperty(String address, String name,
1295d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                                                              String value) {
1296bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        Map <String, String> propVal = mDeviceProperties.get(address);
1297d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (propVal != null) {
1298d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            propVal.put(name, value);
1299bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            mDeviceProperties.put(address, propVal);
1300d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        } else {
1301d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            Log.e(TAG, "setRemoteDeviceProperty for a device not in cache:" + address);
13029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1306efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * Sets the remote device trust state.
1307efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     *
1308efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * @return boolean to indicate operation success or fail
1309efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     */
1310efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    public synchronized boolean setTrust(String address, boolean value) {
1311005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1312e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly            mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1313e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly                    "Need BLUETOOTH_ADMIN permission");
1314efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            return false;
1315efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        }
1316efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue
13178c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
13188c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1319efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        return setDevicePropertyBooleanNative(getObjectPathFromAddress(address), "Trusted",
1320efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue                value ? 1 : 0);
1321efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    }
1322efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue
1323efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    /**
1324efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * Gets the remote device trust state as boolean.
1325efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * Note: this value may be
1326efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * retrieved from cache if we retrieved the data before *
1327efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     *
1328efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * @return boolean to indicate trust or untrust state
1329efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     */
1330efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    public synchronized boolean getTrustState(String address) {
1331005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1332efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1333efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            return false;
1334efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        }
1335efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue
1336efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        String val = getRemoteDeviceProperty(address, "Trusted");
1337efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        if (val == null) {
1338efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            return false;
1339efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        } else {
1340efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            return val.equals("true") ? true : false;
1341efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        }
1342efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    }
1343efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue
1344efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    /**
1345d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Gets the remote major, minor classes encoded as a 32-bit
13469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * integer.
13479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
13489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Note: this value is retrieved from cache, because we get it during
13499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *       remote-device discovery.
13509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
13519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return 32-bit integer encoding the remote major, minor, and service
13529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         classes.
13539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
13549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized int getRemoteClass(String address) {
1355005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1356ea600ccfb7568f60377c4abc85f56c80af7fdbfcNick Pelly            mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1357ea600ccfb7568f60377c4abc85f56c80af7fdbfcNick Pelly            return BluetoothClass.ERROR;
13589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1359d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String val = getRemoteDeviceProperty(address, "Class");
1360d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (val == null)
1361d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return BluetoothClass.ERROR;
1362d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        else {
1363d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return Integer.valueOf(val);
1364d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
13659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1366d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
13679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1369dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh     * Gets the UUIDs supported by the remote device
13709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1371dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh     * @return array of 128bit ParcelUuids
13729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1373dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh    public synchronized ParcelUuid[] getRemoteUuids(String address) {
13749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1375005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
13769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return null;
13779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13781caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        return getUuidFromCache(address);
13791caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    }
13801caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
13811caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    private ParcelUuid[] getUuidFromCache(String address) {
1382d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String value = getRemoteDeviceProperty(address, "UUIDs");
1383dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        if (value == null) return null;
1384dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh
1385dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        String[] uuidStrings = null;
1386d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        // The UUIDs are stored as a "," separated string.
1387dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        uuidStrings = value.split(",");
1388dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        ParcelUuid[] uuids = new ParcelUuid[uuidStrings.length];
1389dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh
1390dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        for (int i = 0; i < uuidStrings.length; i++) {
1391dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh            uuids[i] = ParcelUuid.fromString(uuidStrings[i]);
1392dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        }
1393d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return uuids;
13949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
139616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    /**
139716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * Connect and fetch new UUID's using SDP.
139816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * The UUID's found are broadcast as intents.
139916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * Optionally takes a uuid and callback to fetch the RFCOMM channel for the
140016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * a given uuid.
140116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * TODO: Don't wait UUID_INTENT_DELAY to broadcast UUID intents on success
140216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * TODO: Don't wait UUID_INTENT_DELAY to handle the failure case for
140316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * callback and broadcast intents.
140416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     */
140516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    public synchronized boolean fetchRemoteUuids(String address, ParcelUuid uuid,
140616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            IBluetoothCallback callback) {
14071caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
14088c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
14098c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
14101caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
14111caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            return false;
14121caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        }
14131caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
141416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        RemoteService service = new RemoteService(address, uuid);
141516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        if (uuid != null && mUuidCallbackTracker.get(service) != null) {
141616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            // An SDP query for this address & uuid is already in progress
141716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            // Do not add this callback for the uuid
141816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            return false;
141916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
142016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
14211caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        if (mUuidIntentTracker.contains(address)) {
14221caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            // An SDP query for this address is already in progress
142316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            // Add this uuid onto the in-progress SDP query
142416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (uuid != null) {
142516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                mUuidCallbackTracker.put(new RemoteService(address, uuid), callback);
142616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
14271caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            return true;
14281caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        }
14291caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
14301caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        boolean ret;
14310e09030977aea8b40fd177139528d4b5637c9771Jaikumar Ganesh        // Just do the SDP if the device is already  created and UUIDs are not
14320e09030977aea8b40fd177139528d4b5637c9771Jaikumar Ganesh        // NULL, else create the device and then do SDP.
14330e09030977aea8b40fd177139528d4b5637c9771Jaikumar Ganesh        if (isRemoteDeviceInCache(address) && getRemoteUuids(address) != null) {
14341caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            String path = getObjectPathFromAddress(address);
14351caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            if (path == null) return false;
14361caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
14371caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            // Use an empty string for the UUID pattern
14381caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            ret = discoverServicesNative(path, "");
14391caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        } else {
14401caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            ret = createDeviceNative(address);
14411caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        }
14421caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
14431caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        mUuidIntentTracker.add(address);
144416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        if (uuid != null) {
144516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            mUuidCallbackTracker.put(new RemoteService(address, uuid), callback);
144616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
14471caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
14481caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        Message message = mHandler.obtainMessage(MESSAGE_UUID_INTENT);
14491caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        message.obj = address;
14501caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        mHandler.sendMessageDelayed(message, UUID_INTENT_DELAY);
14511caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        return ret;
14521caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    }
14531caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
14549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1455d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Gets the rfcomm channel associated with the UUID.
145616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * Pulls records from the cache only.
14579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1458d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * @param address Address of the remote device
1459dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh     * @param uuid ParcelUuid of the service attribute
14609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1461d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * @return rfcomm channel associated with the service attribute
146210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh     *         -1 on error
14639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1464dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh    public int getRemoteServiceChannel(String address, ParcelUuid uuid) {
14659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
14668c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return -1;
14678c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1468005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1469b24e11baac589fe16426f2d243b460ab84991c7bNick Pelly            return BluetoothDevice.ERROR;
14709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
147110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        // Check if we are recovering from a crash.
147210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        if (mDeviceProperties.isEmpty()) {
147310eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            if (!updateRemoteDevicePropertiesCache(address))
147410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh                return -1;
147510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        }
147610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
147710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        Map<ParcelUuid, Integer> value = mDeviceServiceChannelCache.get(address);
147810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        if (value != null && value.containsKey(uuid))
147910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            return value.get(uuid);
148010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        return -1;
14819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean setPin(String address, byte[] pin) {
14849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
14859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
14868c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
14878c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
14889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (pin == null || pin.length <= 0 || pin.length > 16 ||
1489005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            !BluetoothAdapter.checkBluetoothAddress(address)) {
14909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
14919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
14929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        address = address.toUpperCase();
14939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
14949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (data == null) {
14959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.w(TAG, "setPin(" + address + ") called but no native data available, " +
14969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                  "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
14979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                  " or by bluez.\n");
14989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
14999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
15009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // bluez API wants pin as a string
15019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String pinString;
15029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
15039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pinString = new String(pin, "UTF8");
15049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (UnsupportedEncodingException uee) {
15059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.e(TAG, "UTF8 not supported?!?");
15069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
15079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
15089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return setPinNative(address, pinString, data.intValue());
15099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
15109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1511b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    public synchronized boolean setPasskey(String address, int passkey) {
1512b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1513b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                                                "Need BLUETOOTH_ADMIN permission");
15148c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
15158c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1516005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (passkey < 0 || passkey > 999999 || !BluetoothAdapter.checkBluetoothAddress(address)) {
1517b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            return false;
1518b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        }
1519b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        address = address.toUpperCase();
1520b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
1521b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        if (data == null) {
1522b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            Log.w(TAG, "setPasskey(" + address + ") called but no native data available, " +
1523b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                  "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
1524b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                  " or by bluez.\n");
1525b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            return false;
1526b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        }
1527b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        return setPasskeyNative(address, passkey, data.intValue());
1528b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    }
1529b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh
1530b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    public synchronized boolean setPairingConfirmation(String address, boolean confirm) {
1531b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1532b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                                                "Need BLUETOOTH_ADMIN permission");
15338c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
15348c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1535b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        address = address.toUpperCase();
1536b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
1537b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        if (data == null) {
1538b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            Log.w(TAG, "setPasskey(" + address + ") called but no native data available, " +
1539b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                  "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
1540b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                  " or by bluez.\n");
1541b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            return false;
1542b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        }
1543b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        return setPairingConfirmationNative(address, confirm, data.intValue());
1544b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    }
1545b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh
1546b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    public synchronized boolean cancelPairingUserInput(String address) {
15479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
15489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
15498c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
15508c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1551005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
15529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
15539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1554005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        mBondState.setBondState(address, BluetoothDevice.BOND_NONE,
1555397d8f4f4829a45f4fe7a672cc395466bbc0f442Jaikumar Ganesh                BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
15569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        address = address.toUpperCase();
15579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
15589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (data == null) {
1559b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            Log.w(TAG, "cancelUserInputNative(" + address + ") called but no native data " +
1560b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                "available, ignoring. Maybe the PasskeyAgent Request was already cancelled " +
1561b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                "by the remote or by bluez.\n");
15629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
15639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1564b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        return cancelPairingUserInputNative(address, data.intValue());
15659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
15669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15678c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh    /*package*/ void updateDeviceServiceChannelCache(String address) {
156810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        ParcelUuid[] deviceUuids = getRemoteUuids(address);
156910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        // We are storing the rfcomm channel numbers only for the uuids
157010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        // we are interested in.
157110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        int channel;
157216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        if (DBG) log("updateDeviceServiceChannelCache(" + address + ")");
157316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
157416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        ArrayList<ParcelUuid> applicationUuids = new ArrayList();
157516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
157616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        synchronized (this) {
157716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            for (RemoteService service : mUuidCallbackTracker.keySet()) {
157816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (service.address.equals(address)) {
157916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    applicationUuids.add(service.uuid);
158016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                }
158116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
158216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
158310eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
158410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        Map <ParcelUuid, Integer> value = new HashMap<ParcelUuid, Integer>();
158516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
158616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        // Retrieve RFCOMM channel for default uuids
158716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        for (ParcelUuid uuid : RFCOMM_UUIDS) {
158810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            if (BluetoothUuid.isUuidPresent(deviceUuids, uuid)) {
158916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                channel = getDeviceServiceChannelNative(getObjectPathFromAddress(address),
159016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        uuid.toString(), 0x0004);
159116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (DBG) log("\tuuid(system): " + uuid + " " + channel);
159210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh                value.put(uuid, channel);
159310eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            }
159410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        }
159516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        // Retrieve RFCOMM channel for application requested uuids
159616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        for (ParcelUuid uuid : applicationUuids) {
159716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (BluetoothUuid.isUuidPresent(deviceUuids, uuid)) {
159816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                channel = getDeviceServiceChannelNative(getObjectPathFromAddress(address),
159916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        uuid.toString(), 0x0004);
160016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (DBG) log("\tuuid(application): " + uuid + " " + channel);
160116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                value.put(uuid, channel);
160216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
160316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
160416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
160516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        synchronized (this) {
160616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            // Make application callbacks
160716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            for (Iterator<RemoteService> iter = mUuidCallbackTracker.keySet().iterator();
160816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    iter.hasNext();) {
160916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                RemoteService service = iter.next();
161016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (service.address.equals(address)) {
161116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    channel = -1;
161216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    if (value.get(service.uuid) != null) {
161316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        channel = value.get(service.uuid);
161416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    }
161516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    if (channel != -1) {
161616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        if (DBG) log("Making callback for " + service.uuid + " with result " +
161716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                                channel);
161816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        IBluetoothCallback callback = mUuidCallbackTracker.get(service);
161916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        if (callback != null) {
162016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                            try {
162116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                                callback.onRfcommChannelFound(channel);
162216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                            } catch (RemoteException e) {Log.e(TAG, "", e);}
162316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        }
162416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
162516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        iter.remove();
162616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    }
162716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                }
162816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
162916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
163016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            // Update cache
163116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            mDeviceServiceChannelCache.put(address, value);
163216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
163310eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh    }
163410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
163524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    /**
163624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     * b is a handle to a Binder instance, so that this service can be notified
163724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     * for Applications that terminate unexpectedly, to clean there service
163824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     * records
163924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     */
164024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    public synchronized int addRfcommServiceRecord(String serviceName, ParcelUuid uuid,
164124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            int channel, IBinder b) {
16428c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
16438c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return -1;
16448c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
164524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (serviceName == null || uuid == null || channel < 1 ||
164624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                channel > BluetoothSocket.MAX_RFCOMM_CHANNEL) {
164724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            return -1;
164824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
164924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (BluetoothUuid.isUuidPresent(BluetoothUuid.RESERVED_UUIDS, uuid)) {
165024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            Log.w(TAG, "Attempted to register a reserved UUID: " + uuid);
165124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            return -1;
165224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
165324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        int handle = addRfcommServiceRecordNative(serviceName,
165424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                uuid.getUuid().getMostSignificantBits(), uuid.getUuid().getLeastSignificantBits(),
165524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                (short)channel);
165624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (DBG) log("new handle " + Integer.toHexString(handle));
165724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (handle == -1) {
165824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            return -1;
165924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
166024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
166124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        int pid = Binder.getCallingPid();
166224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        mServiceRecordToPid.put(new Integer(handle), new Integer(pid));
166324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        try {
166424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            b.linkToDeath(new Reaper(handle, pid), 0);
166524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        } catch (RemoteException e) {}
166624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        return handle;
166724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    }
166824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
166924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    public void removeServiceRecord(int handle) {
167024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
167124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                                                "Need BLUETOOTH permission");
167224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        checkAndRemoveRecord(handle, Binder.getCallingPid());
167324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    }
167424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
167524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private synchronized void checkAndRemoveRecord(int handle, int pid) {
167624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        Integer handleInt = new Integer(handle);
167724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        Integer owner = mServiceRecordToPid.get(handleInt);
167824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (owner != null && pid == owner.intValue()) {
167924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            if (DBG) log("Removing service record " + Integer.toHexString(handle) + " for pid " +
168024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                    pid);
168124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            mServiceRecordToPid.remove(handleInt);
168224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            removeServiceRecordNative(handle);
168324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
168424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    }
168524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
168624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private class Reaper implements IBinder.DeathRecipient {
168724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        int pid;
168824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        int handle;
168924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        Reaper(int handle, int pid) {
169024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            this.pid = pid;
169124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            this.handle = handle;
169224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
169324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        public void binderDied() {
169424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            synchronized (BluetoothService.this) {
169524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                if (DBG) log("Tracked app " + pid + " died");
169624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                checkAndRemoveRecord(handle, pid);
169724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            }
169824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
169924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    }
170024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
17019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
17029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
17039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onReceive(Context context, Intent intent) {
17046e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh            if (intent == null) return;
17056e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh
17069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String action = intent.getAction();
17079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
17089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ContentResolver resolver = context.getContentResolver();
17099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Query the airplane mode from Settings.System just to make sure that
17109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // some random app is not sending this intent and disabling bluetooth
17119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                boolean enabled = !isAirplaneModeOn();
17129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // If bluetooth is currently expected to be on, then enable or disable bluetooth
17139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (Settings.Secure.getInt(resolver, Settings.Secure.BLUETOOTH_ON, 0) > 0) {
17149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (enabled) {
1715105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                        enable(false);
17169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } else {
17179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        disable(false);
17189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
17199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
17206e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh            } else if (Intent.ACTION_DOCK_EVENT.equals(action)) {
17216e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                int state = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
17226e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                        Intent.EXTRA_DOCK_STATE_UNDOCKED);
17236e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                if (DBG) Log.v(TAG, "Received ACTION_DOCK_EVENT with State:" + state);
17246e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                if (state == Intent.EXTRA_DOCK_STATE_UNDOCKED) {
17256e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                    mDockAddress = null;
17266e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                    mDockPin = null;
17276e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                } else {
17286e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                    SharedPreferences.Editor editor =
17296e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                        mContext.getSharedPreferences(SHARED_PREFERENCES_NAME,
17306e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                                mContext.MODE_PRIVATE).edit();
17316e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                    editor.putBoolean(SHARED_PREFERENCE_DOCK_ADDRESS + mDockAddress, true);
17326e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                    editor.commit();
17336e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                }
17349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
17359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
17369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
17379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17386e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh    private void registerForAirplaneMode(IntentFilter filter) {
173944303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        final ContentResolver resolver = mContext.getContentResolver();
174044303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        final String airplaneModeRadios = Settings.System.getString(resolver,
17419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Settings.System.AIRPLANE_MODE_RADIOS);
174244303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        final String toggleableRadios = Settings.System.getString(resolver,
174344303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey                Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
174444303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey
174544303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        mIsAirplaneSensitive = airplaneModeRadios == null ? true :
174644303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey                airplaneModeRadios.contains(Settings.System.RADIO_BLUETOOTH);
174744303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        mIsAirplaneToggleable = toggleableRadios == null ? false :
174844303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey                toggleableRadios.contains(Settings.System.RADIO_BLUETOOTH);
174944303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey
17509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mIsAirplaneSensitive) {
17516e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh            filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
17529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
17539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
17549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* Returns true if airplane mode is currently on */
17569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final boolean isAirplaneModeOn() {
17579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return Settings.System.getInt(mContext.getContentResolver(),
17589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Settings.System.AIRPLANE_MODE_ON, 0) == 1;
17599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
17609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17611caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    /* Broadcast the Uuid intent */
17621caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    /*package*/ synchronized void sendUuidIntent(String address) {
17636179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh        ParcelUuid[] uuid = getUuidFromCache(address);
17646179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh        Intent intent = new Intent(BluetoothDevice.ACTION_UUID);
17652d3b98d868cda30535505b2a2fba47aa1c9c052bJaikumar Ganesh        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
17666179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh        intent.putExtra(BluetoothDevice.EXTRA_UUID, uuid);
17676179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh        mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
17681caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
17696179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh        if (mUuidIntentTracker.contains(address))
17701caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            mUuidIntentTracker.remove(address);
177116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
177216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    }
177316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
177416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    /*package*/ synchronized void makeServiceChannelCallbacks(String address) {
177516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        for (Iterator<RemoteService> iter = mUuidCallbackTracker.keySet().iterator();
177616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                iter.hasNext();) {
177716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            RemoteService service = iter.next();
177816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (service.address.equals(address)) {
177916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (DBG) log("Cleaning up failed UUID channel lookup: " + service.address +
178016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        " " + service.uuid);
178116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                IBluetoothCallback callback = mUuidCallbackTracker.get(service);
178216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (callback != null) {
178316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    try {
178416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        callback.onRfcommChannelFound(-1);
178516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    } catch (RemoteException e) {Log.e(TAG, "", e);}
178616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                }
178716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
178816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                iter.remove();
178916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
179016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
17911caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    }
17921caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
17939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
17949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1795105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        switch(mBluetoothState) {
1796de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_OFF:
179724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            pw.println("Bluetooth OFF\n");
1798105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return;
1799de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_TURNING_ON:
180024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            pw.println("Bluetooth TURNING ON\n");
1801105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return;
1802de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_TURNING_OFF:
180324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            pw.println("Bluetooth TURNING OFF\n");
1804105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return;
1805de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_ON:
180624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            pw.println("Bluetooth ON\n");
1807105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
1808105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
180924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("mIsAirplaneSensitive = " + mIsAirplaneSensitive);
181044303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        pw.println("mIsAirplaneToggleable = " + mIsAirplaneToggleable);
181124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
181224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("Local address = " + getAddress());
181324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("Local name = " + getName());
181424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("isDiscovering() = " + isDiscovering());
1815105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
1816105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        BluetoothHeadset headset = new BluetoothHeadset(mContext, null);
1817105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
1818105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        pw.println("\n--Known devices--");
1819bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        for (String address : mDeviceProperties.keySet()) {
18201eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly            int bondState = mBondState.getBondState(address);
1821105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            pw.printf("%s %10s (%d) %s\n", address,
18221eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly                       toBondStateString(bondState),
1823105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                       mBondState.getAttempt(address),
1824105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                       getRemoteName(address));
182524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
182624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            Map<ParcelUuid, Integer> uuidChannels = mDeviceServiceChannelCache.get(address);
182724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            if (uuidChannels == null) {
182824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                pw.println("\tuuids = null");
182924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            } else {
183024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                for (ParcelUuid uuid : uuidChannels.keySet()) {
183124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                    Integer channel = uuidChannels.get(uuid);
183224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                    if (channel == null) {
183324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                        pw.println("\t" + uuid);
183424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                    } else {
183524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                        pw.println("\t" + uuid + " RFCOMM channel = " + channel);
18361eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly                    }
18371eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly                }
18381eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly            }
183916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            for (RemoteService service : mUuidCallbackTracker.keySet()) {
184016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (service.address.equals(address)) {
184116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    pw.println("\tPENDING CALLBACK: " + service.uuid);
184216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                }
184316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
1844105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
1845105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
1846d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String value = getProperty("Devices");
18471eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly        String[] devicesObjectPath = null;
1848d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (value != null) {
1849d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            devicesObjectPath = value.split(",");
1850d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
1851105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        pw.println("\n--ACL connected devices--");
185224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (devicesObjectPath != null) {
185324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            for (String device : devicesObjectPath) {
185424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                pw.println(getAddressFromObjectPath(device));
185524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            }
1856105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
1857105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
1858105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Rather not do this from here, but no-where else and I need this
1859105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // dump
1860105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        pw.println("\n--Headset Service--");
1861740e39be6af3e366a4b82c030b5ea67ab144b42aJaikumar Ganesh        switch (headset.getState(headset.getCurrentHeadset())) {
1862105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        case BluetoothHeadset.STATE_DISCONNECTED:
1863105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            pw.println("getState() = STATE_DISCONNECTED");
1864105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            break;
1865105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        case BluetoothHeadset.STATE_CONNECTING:
1866105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            pw.println("getState() = STATE_CONNECTING");
1867105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            break;
1868105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        case BluetoothHeadset.STATE_CONNECTED:
1869105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            pw.println("getState() = STATE_CONNECTED");
1870105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            break;
1871105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        case BluetoothHeadset.STATE_ERROR:
1872105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            pw.println("getState() = STATE_ERROR");
1873105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            break;
1874105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
18756c901db72dbaf57d8fdf26adae6721de14ecae22Nick Pelly
187624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("\ngetCurrentHeadset() = " + headset.getCurrentHeadset());
187724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("getBatteryUsageHint() = " + headset.getBatteryUsageHint());
1878105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        headset.close();
187924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("\n--Application Service Records--");
188024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        for (Integer handle : mServiceRecordToPid.keySet()) {
188124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            Integer pid = mServiceRecordToPid.get(handle);
188224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            pw.println("\tpid " + pid + " handle " + Integer.toHexString(handle));
188324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
18849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
18859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1886d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ static int bluezStringToScanMode(boolean pairable, boolean discoverable) {
1887d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (pairable && discoverable)
1888bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            return BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE;
1889d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        else if (pairable && !discoverable)
1890bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            return BluetoothAdapter.SCAN_MODE_CONNECTABLE;
1891d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        else
1892bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            return BluetoothAdapter.SCAN_MODE_NONE;
18939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
18949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* package */ static String scanModeToBluezString(int mode) {
18969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        switch (mode) {
1897bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        case BluetoothAdapter.SCAN_MODE_NONE:
18989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "off";
1899bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
19009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "connectable";
1901bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
19029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "discoverable";
19039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
19049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return null;
19059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
19069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1907d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /*package*/ String getAddressFromObjectPath(String objectPath) {
1908b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh        String adapterObjectPath = getPropertyInternal("ObjectPath");
1909d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (adapterObjectPath == null || objectPath == null) {
1910d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            Log.e(TAG, "getAddressFromObjectPath: AdpaterObjectPath:" + adapterObjectPath +
1911d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                    "  or deviceObjectPath:" + objectPath + " is null");
1912d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return null;
1913d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
1914d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (!objectPath.startsWith(adapterObjectPath)) {
1915d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            Log.e(TAG, "getAddressFromObjectPath: AdpaterObjectPath:" + adapterObjectPath +
1916d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                    "  is not a prefix of deviceObjectPath:" + objectPath +
1917d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                    "bluetoothd crashed ?");
1918d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return null;
1919d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
1920d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String address = objectPath.substring(adapterObjectPath.length());
1921d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (address != null) return address.replace('_', ':');
1922d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1923d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        Log.e(TAG, "getAddressFromObjectPath: Address being returned is null");
1924d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return null;
1925d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
1926d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1927d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /*package*/ String getObjectPathFromAddress(String address) {
1928b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh        String path = getPropertyInternal("ObjectPath");
1929d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (path == null) {
1930d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            Log.e(TAG, "Error: Object Path is null");
1931d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return null;
1932d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
1933d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        path = path + address.replace(":", "_");
1934d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return path;
1935d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
1936d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1937b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh    /*package */ void setLinkTimeout(String address, int num_slots) {
1938b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh        String path = getObjectPathFromAddress(address);
1939b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh        boolean result = setLinkTimeoutNative(path, num_slots);
1940b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh
1941b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh        if (!result) log("Set Link Timeout to:" + num_slots + " slots failed");
1942b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh    }
1943b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh
19449b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public boolean connectHeadset(String address) {
19459b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        BluetoothProfileConnectionState state = mProfileConnectionMgr.get(address);
19469b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (state != null) {
19479b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh          state.sendMessage(BluetoothProfileConnectionState.CONNECT_HFP_OUTGOING);
19489b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh          return true;
19499b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
19509b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        return false;
19519b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
19529b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
19539b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public boolean disconnectHeadset(String address) {
19549b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        BluetoothProfileConnectionState state = mProfileConnectionMgr.get(address);
19559b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (state != null) {
19569b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            state.sendMessage(BluetoothProfileConnectionState.DISCONNECT_HFP_OUTGOING);
19579b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            return true;
19589b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
19599b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        return false;
19609b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
19619b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
19629b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public boolean connectSink(String address) {
19639b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        BluetoothProfileConnectionState state = mProfileConnectionMgr.get(address);
19649b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (state != null) {
19659b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh          state.sendMessage(BluetoothProfileConnectionState.CONNECT_A2DP_OUTGOING);
19669b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh          return true;
19679b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
19689b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        return false;
19699b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
19709b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
19719b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public boolean disconnectSink(String address) {
19729b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        BluetoothProfileConnectionState state = mProfileConnectionMgr.get(address);
19739b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (state != null) {
19749b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            state.sendMessage(BluetoothProfileConnectionState.DISCONNECT_A2DP_OUTGOING);
19759b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            return true;
19769b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
19779b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        return false;
19789b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
19799b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
19809b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    private BluetoothProfileConnectionState addProfileState(String address) {
19819b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        BluetoothProfileConnectionState state = mProfileConnectionMgr.get(address);
19829b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (state != null) return state;
19839b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
19849b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        state = new BluetoothProfileConnectionState(mContext, address, this, mA2dpService);
19859b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        mProfileConnectionMgr.put(address, state);
19869b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        state.start();
19879b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        return state;
19889b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
19899b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
19909b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    private void removeProfileState(String address) {
19919b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        mProfileConnectionMgr.remove(address);
19929b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
19939b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
19949b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    private void initProfileState() {
19959b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        String []bonds = null;
19969b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        String val = getPropertyInternal("Devices");
19979b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (val != null) {
19989b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            bonds = val.split(",");
19999b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
20009b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (bonds == null) {
20019b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            return;
20029b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
20039b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
20049b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        for (String path : bonds) {
20059b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            String address = getAddressFromObjectPath(path);
20069b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            BluetoothProfileConnectionState state = addProfileState(address);
20079b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            // Allow 8 secs for SDP records to get registered.
20089b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            Message msg = new Message();
20099b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            msg.what = BluetoothProfileConnectionState.AUTO_CONNECT_PROFILES;
20109b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            state.sendMessageDelayed(msg, 8000);
20119b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
20129b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
20139b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
20149b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public boolean notifyIncomingConnection(String address) {
20159b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        BluetoothProfileConnectionState state =
20169b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh             mProfileConnectionMgr.get(address);
20179b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (state != null) {
20189b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            Message msg = new Message();
20199b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            msg.what = BluetoothProfileConnectionState.CONNECT_HFP_INCOMING;
20209b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            state.sendMessage(msg);
20219b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            return true;
20229b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
20239b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        return false;
20249b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
20259b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
20269b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    /*package*/ boolean notifyIncomingA2dpConnection(String address) {
20279b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh       BluetoothProfileConnectionState state =
20289b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            mProfileConnectionMgr.get(address);
20299b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh       if (state != null) {
20309b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh           Message msg = new Message();
20319b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh           msg.what = BluetoothProfileConnectionState.CONNECT_A2DP_INCOMING;
20329b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh           state.sendMessage(msg);
20339b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh           return true;
20349b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh       }
20359b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh       return false;
20369b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
20379b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
20389b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    /*package*/ void setA2dpService(BluetoothA2dpService a2dpService) {
20399b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        mA2dpService = a2dpService;
20409b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
20419b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
20429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static void log(String msg) {
20439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Log.d(TAG, msg);
20449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2045d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
2046d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native static void classInitNative();
2047d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native void initializeNativeDataNative();
2048d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setupNativeDataNative();
2049d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean tearDownNativeDataNative();
2050d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native void cleanupNativeDataNative();
2051d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native String getAdapterPathNative();
2052d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
2053d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native int isEnabledNative();
2054d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native int enableNative();
2055d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native int disableNative();
2056d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
2057d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native Object[] getAdapterPropertiesNative();
2058d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native Object[] getDevicePropertiesNative(String objectPath);
2059d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setAdapterPropertyStringNative(String key, String value);
2060d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setAdapterPropertyIntegerNative(String key, int value);
2061d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setAdapterPropertyBooleanNative(String key, int value);
2062d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
2063d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean startDiscoveryNative();
2064d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean stopDiscoveryNative();
2065d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
2066d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean createPairedDeviceNative(String address, int timeout_ms);
2067d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean cancelDeviceCreationNative(String address);
2068d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean removeDeviceNative(String objectPath);
2069d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native int getDeviceServiceChannelNative(String objectPath, String uuid,
2070d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            int attributeId);
2071d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
2072b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    private native boolean cancelPairingUserInputNative(String address, int nativeData);
2073d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setPinNative(String address, String pin, int nativeData);
2074b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    private native boolean setPasskeyNative(String address, int passkey, int nativeData);
2075b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    private native boolean setPairingConfirmationNative(String address, boolean confirm,
2076b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            int nativeData);
207724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private native boolean setDevicePropertyBooleanNative(String objectPath, String key,
207824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            int value);
20791caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    private native boolean createDeviceNative(String address);
208016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    /*package*/ native boolean discoverServicesNative(String objectPath, String pattern);
208110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
208224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private native int addRfcommServiceRecordNative(String name, long uuidMsb, long uuidLsb,
208324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            short channel);
208424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private native boolean removeServiceRecordNative(int handle);
2085b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh    private native boolean setLinkTimeoutNative(String path, int num_slots);
20869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
2087