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;
3124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pellyimport android.bluetooth.BluetoothSocket;
3210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganeshimport android.bluetooth.BluetoothUuid;
33bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pellyimport android.bluetooth.IBluetooth;
3416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pellyimport android.bluetooth.IBluetoothCallback;
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.BroadcastReceiver;
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ContentResolver;
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Intent;
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.IntentFilter;
406e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganeshimport android.content.SharedPreferences;
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Binder;
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Handler;
433fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport android.os.IBinder;
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Message;
453fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport android.os.ParcelUuid;
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.RemoteException;
47105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Projectimport android.os.ServiceManager;
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemService;
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.Settings;
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log;
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
52d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganeshimport com.android.internal.app.IBatteryStats;
53d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
543fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.BufferedInputStream;
55c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganeshimport java.io.BufferedReader;
563fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.BufferedWriter;
57c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganeshimport java.io.DataInputStream;
58c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganeshimport java.io.File;
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileDescriptor;
603fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.FileInputStream;
613fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.FileNotFoundException;
62c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganeshimport java.io.FileOutputStream;
633fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.FileWriter;
643fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.IOException;
65c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganeshimport java.io.InputStreamReader;
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.PrintWriter;
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.UnsupportedEncodingException;
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList;
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Arrays;
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.HashMap;
7116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pellyimport java.util.Iterator;
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Map;
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
74bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pellypublic class BluetoothService extends IBluetooth.Stub {
75bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    private static final String TAG = "BluetoothService";
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final boolean DBG = true;
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mNativeData;
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private BluetoothEventLoop mEventLoop;
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mIsAirplaneSensitive;
8144303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey    private boolean mIsAirplaneToggleable;
82105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private int mBluetoothState;
83997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly    private boolean mRestart = false;  // need to call enable() after disable()
84bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    private boolean mIsDiscovering;
85997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly
86bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    private BluetoothAdapter mAdapter;  // constant after init()
87997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly    private final BondState mBondState = new BondState();  // local cache of bondings
88105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private final IBatteryStats mBatteryStats;
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final Context mContext;
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
943fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    private static final String DOCK_ADDRESS_PATH = "/sys/class/switch/dock/bt_addr";
953fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    private static final String DOCK_PIN_PATH = "/sys/class/switch/dock/bt_pin";
963fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
976e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh    private static final String SHARED_PREFERENCE_DOCK_ADDRESS = "dock_bluetooth_address";
986e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh    private static final String SHARED_PREFERENCES_NAME = "bluetooth_service_settings";
996e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh
100105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private static final int MESSAGE_REGISTER_SDP_RECORDS = 1;
101105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private static final int MESSAGE_FINISH_DISABLE = 2;
1021caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    private static final int MESSAGE_UUID_INTENT = 3;
10312835478ee687a493d1b5882e67b6725bd539c26Nick Pelly    private static final int MESSAGE_DISCOVERABLE_TIMEOUT = 4;
1041caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
1051caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    // The timeout used to sent the UUIDs Intent
1061caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    // This timeout should be greater than the page timeout
1071caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    private static final int UUID_INTENT_DELAY = 6000;
108105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
10916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    /** Always retrieve RFCOMM channel for these SDP UUIDs */
11016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private static final ParcelUuid[] RFCOMM_UUIDS = {
11116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            BluetoothUuid.Handsfree,
11216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            BluetoothUuid.HSP,
11316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            BluetoothUuid.ObexObjectPush };
11416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
11516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
116bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    private final Map<String, String> mAdapterProperties;
11716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private final HashMap<String, Map<String, String>> mDeviceProperties;
118d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
11916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private final HashMap<String, Map<ParcelUuid, Integer>> mDeviceServiceChannelCache;
12016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private final ArrayList<String> mUuidIntentTracker;
12116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private final HashMap<RemoteService, IBluetoothCallback> mUuidCallbackTracker;
1221caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
12324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private final HashMap<Integer, Integer> mServiceRecordToPid;
12424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
1253fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    private static String mDockAddress;
1263fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    private String mDockPin;
1273fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
12816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private static class RemoteService {
12916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        public String address;
13016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        public ParcelUuid uuid;
13116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        public RemoteService(String address, ParcelUuid uuid) {
13216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            this.address = address;
13316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            this.uuid = uuid;
13416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
13516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        @Override
13616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        public boolean equals(Object o) {
13716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (o instanceof RemoteService) {
13816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                RemoteService service = (RemoteService)o;
13916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                return address.equals(service.address) && uuid.equals(service.uuid);
14016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
14116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            return false;
14216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
1435f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root
1445f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root        @Override
1455f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root        public int hashCode() {
1465f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root            int hash = 1;
1475f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root            hash = hash * 31 + (address == null ? 0 : address.hashCode());
1485f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root            hash = hash * 31 + (uuid == null ? 0 : uuid.hashCode());
1495f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root            return hash;
1505f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root        }
15116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    }
15216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static {
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        classInitNative();
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
157bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    public BluetoothService(Context context) {
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext = context;
159105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
160105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Need to do this in place of:
161105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // mBatteryStats = BatteryStatsService.getService();
162105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Since we can not import BatteryStatsService from here. This class really needs to be
163105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // moved to java/services/com/android/server/
164105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo"));
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        initializeNativeDataNative();
167ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project
168ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project        if (isEnabledNative() == 1) {
169ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project            Log.w(TAG, "Bluetooth daemons already running - runtime restart? ");
170ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project            disableNative();
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
172ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project
173de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        mBluetoothState = BluetoothAdapter.STATE_OFF;
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mIsDiscovering = false;
175bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mAdapterProperties = new HashMap<String, String>();
176bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mDeviceProperties = new HashMap<String, Map<String,String>>();
17710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
17810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        mDeviceServiceChannelCache = new HashMap<String, Map<ParcelUuid, Integer>>();
1791caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        mUuidIntentTracker = new ArrayList<String>();
18016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        mUuidCallbackTracker = new HashMap<RemoteService, IBluetoothCallback>();
18124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        mServiceRecordToPid = new HashMap<Integer, Integer>();
1823fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
1833fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        IntentFilter filter = new IntentFilter();
1846e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh        registerForAirplaneMode(filter);
1856e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh
1863fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        filter.addAction(Intent.ACTION_DOCK_EVENT);
1876e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh        mContext.registerReceiver(mReceiver, filter);
1883fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    }
1893fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
1903fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh     public static synchronized String readDockBluetoothAddress() {
1913fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        if (mDockAddress != null) return mDockAddress;
1923fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
1933fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        BufferedInputStream file = null;
1943fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        String dockAddress;
1953fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        try {
1963fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            file = new BufferedInputStream(new FileInputStream(DOCK_ADDRESS_PATH));
1973fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            byte[] address = new byte[17];
1983fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            file.read(address);
1993fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            dockAddress = new String(address);
2003fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            dockAddress = dockAddress.toUpperCase();
2013fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            if (BluetoothAdapter.checkBluetoothAddress(dockAddress)) {
2023fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                mDockAddress = dockAddress;
2033fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                return mDockAddress;
2043fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            } else {
2053fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                log("CheckBluetoothAddress failed for car dock address:" + dockAddress);
2063fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            }
2073fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        } catch (FileNotFoundException e) {
2083fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            log("FileNotFoundException while trying to read dock address");
2093fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        } catch (IOException e) {
2103fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            log("IOException while trying to read dock address");
2113fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        } finally {
2123fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            if (file != null) {
2133fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                try {
2143fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                    file.close();
2153fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                } catch (IOException e) {
2163fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                    // Ignore
2173fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                }
2183fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            }
2193fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        }
2203fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        mDockAddress = null;
2213fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        return null;
2223fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    }
2233fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
2243fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    private synchronized boolean writeDockPin() {
2253fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        BufferedWriter out = null;
2263fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        try {
2273fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            out = new BufferedWriter(new FileWriter(DOCK_PIN_PATH));
2283fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
2293fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            // Generate a random 4 digit pin between 0000 and 9999
2303fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            // This is not truly random but good enough for our purposes.
2313fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            int pin = (int) Math.floor(Math.random() * 10000);
2323fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
2333fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            mDockPin = String.format("%04d", pin);
2343fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            out.write(mDockPin);
2353fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            return true;
2363fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        } catch (FileNotFoundException e) {
2373fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            log("FileNotFoundException while trying to write dock pairing pin");
2383fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        } catch (IOException e) {
2393fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            log("IOException while while trying to write dock pairing pin");
2403fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        } finally {
2413fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            if (out != null) {
2423fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                try {
2433fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                    out.close();
2443fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                } catch (IOException e) {
2453fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                    // Ignore
2463fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                }
2473fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            }
2483fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        }
2493fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        mDockPin = null;
2503fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        return false;
2513fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    }
2523fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
2533fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    /*package*/ synchronized String getDockPin() {
2543fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        return mDockPin;
255bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    }
256bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly
257bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    public synchronized void initAfterRegistration() {
258f242b7b931898856bcbcb7ec36cacf43098ba544Nick Pelly        mAdapter = BluetoothAdapter.getDefaultAdapter();
259bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mEventLoop = new BluetoothEventLoop(mContext, mAdapter, this);
2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void finalize() throws Throwable {
2646e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh        mContext.unregisterReceiver(mReceiver);
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            cleanupNativeDataNative();
2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super.finalize();
2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean isEnabled() {
2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
2748c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        return isEnabledInternal();
2758c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh    }
2768c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
2778c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh    private boolean isEnabledInternal() {
278de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        return mBluetoothState == BluetoothAdapter.STATE_ON;
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
281105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    public int getBluetoothState() {
282105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
283105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        return mBluetoothState;
284105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    }
285105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
286105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Bring down bluetooth and disable BT in settings. Returns true on success.
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean disable() {
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return disable(true);
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Bring down bluetooth. Returns true on success.
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
297e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly     * @param saveSetting If true, persist the new setting
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean disable(boolean saveSetting) {
300e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission");
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
302105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        switch (mBluetoothState) {
303de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_OFF:
304105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return true;
305de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_ON:
306105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            break;
307105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        default:
308105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return false;
309105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mEnableThread != null && mEnableThread.isAlive()) {
3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
313de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        setBluetoothState(BluetoothAdapter.STATE_TURNING_OFF);
314bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly        mHandler.removeMessages(MESSAGE_REGISTER_SDP_RECORDS);
315105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
316105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Allow 3 seconds for profiles to gracefully disconnect
317105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // TODO: Introduce a callback mechanism so that each profile can notify
318bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        // BluetoothService when it is done shutting down
319105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mHandler.sendMessageDelayed(
320105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                mHandler.obtainMessage(MESSAGE_FINISH_DISABLE, saveSetting ? 1 : 0, 0), 3000);
321105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        return true;
322105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    }
323105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
324105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
325105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private synchronized void finishDisable(boolean saveSetting) {
326de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        if (mBluetoothState != BluetoothAdapter.STATE_TURNING_OFF) {
327105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return;
3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mEventLoop.stop();
330d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        tearDownNativeDataNative();
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        disableNative();
3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // mark in progress bondings as cancelled
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (String address : mBondState.listInState(BluetoothDevice.BOND_BONDING)) {
335005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            mBondState.setBondState(address, BluetoothDevice.BOND_NONE,
3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // update mode
340de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        Intent intent = new Intent(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
341de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        intent.putExtra(BluetoothAdapter.EXTRA_SCAN_MODE, BluetoothAdapter.SCAN_MODE_NONE);
3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.sendBroadcast(intent, BLUETOOTH_PERM);
3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
344105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mIsDiscovering = false;
345bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mAdapterProperties.clear();
34624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        mServiceRecordToPid.clear();
347105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (saveSetting) {
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            persistBluetoothOnSetting(false);
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
351105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
352de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        setBluetoothState(BluetoothAdapter.STATE_OFF);
353105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
354105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Log bluetooth off to battery stats.
355105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        long ident = Binder.clearCallingIdentity();
356105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        try {
357105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            mBatteryStats.noteBluetoothOff();
358105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        } catch (RemoteException e) {
359105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        } finally {
360105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            Binder.restoreCallingIdentity(ident);
361105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
362997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly
363997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        if (mRestart) {
364997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly            mRestart = false;
365997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly            enable();
366997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        }
3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
369105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    /** Bring up BT and persist BT on in settings */
370105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    public boolean enable() {
371105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        return enable(true);
3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Enable this Bluetooth device, asynchronously.
3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * This turns on/off the underlying hardware.
3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
378105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project     * @param saveSetting If true, persist the new state of BT in settings
379105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project     * @return True on success (so far)
3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
381105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    public synchronized boolean enable(boolean saveSetting) {
3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Airplane mode can prevent Bluetooth radio from being turned on.
38644303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        if (mIsAirplaneSensitive && isAirplaneModeOn() && !mIsAirplaneToggleable) {
3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
389de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        if (mBluetoothState != BluetoothAdapter.STATE_OFF) {
3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mEnableThread != null && mEnableThread.isAlive()) {
3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
395de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        setBluetoothState(BluetoothAdapter.STATE_TURNING_ON);
396105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mEnableThread = new EnableThread(saveSetting);
3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mEnableThread.start();
3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
401997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly    /** Forcibly restart Bluetooth if it is on */
402997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly    /* package */ synchronized void restart() {
403de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        if (mBluetoothState != BluetoothAdapter.STATE_ON) {
404997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly            return;
405997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        }
406997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        mRestart = true;
407997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        if (!disable(false)) {
408997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly            mRestart = false;
409997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        }
410d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
411997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly
412105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private synchronized void setBluetoothState(int state) {
413105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        if (state == mBluetoothState) {
414105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return;
415105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
416105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
417105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        if (DBG) log("Bluetooth state " + mBluetoothState + " -> " + state);
418105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
419de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
420de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, mBluetoothState);
421de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        intent.putExtra(BluetoothAdapter.EXTRA_STATE, state);
422105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
423105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
424105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mBluetoothState = state;
425105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
426105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mContext.sendBroadcast(intent, BLUETOOTH_PERM);
427105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    }
428105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final Handler mHandler = new Handler() {
4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void handleMessage(Message msg) {
4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            switch (msg.what) {
433105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            case MESSAGE_REGISTER_SDP_RECORDS:
4348c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh                if (!isEnabledInternal()) {
435bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    return;
436bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                }
437bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                // SystemService.start() forks sdptool to register service
438bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                // records. It can fail to register some records if it is
439bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                // forked multiple times in a row, probably because there is
440bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                // some race in sdptool or bluez when operated in parallel.
441bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                // As a workaround, delay 500ms between each fork of sdptool.
442bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                // TODO: Don't fork sdptool in order to regsiter service
443bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                // records, use a DBUS call instead.
444bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                switch (msg.arg1) {
445bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                case 1:
44677b4ad0e496941a28382eb938a05831f1f8d2d4aJaikumar Ganesh                    Log.d(TAG, "Registering hfag record");
44777b4ad0e496941a28382eb938a05831f1f8d2d4aJaikumar Ganesh                    SystemService.start("hfag");
448bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    mHandler.sendMessageDelayed(
449bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                            mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS, 2, -1), 500);
450bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    break;
451bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                case 2:
45277b4ad0e496941a28382eb938a05831f1f8d2d4aJaikumar Ganesh                    Log.d(TAG, "Registering hsag record");
45377b4ad0e496941a28382eb938a05831f1f8d2d4aJaikumar Ganesh                    SystemService.start("hsag");
454bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    mHandler.sendMessageDelayed(
455bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                            mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS, 3, -1), 500);
456bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    break;
457bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                case 3:
458bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    Log.d(TAG, "Registering opush record");
45903c707ab6fc97e99b1603b8d6edc604dbea3cd6fNick Pelly                    SystemService.start("opush");
460bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    mHandler.sendMessageDelayed(
461bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                            mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS, 4, -1), 500);
462bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    break;
463bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                case 4:
464bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    Log.d(TAG, "Registering pbap record");
46567542964876aa7e4216e8f69f21dda68e7463b9aJaikumar Ganesh                    SystemService.start("pbap");
466bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    break;
4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
468105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                break;
469105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            case MESSAGE_FINISH_DISABLE:
470105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                finishDisable(msg.arg1 != 0);
471105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                break;
4721caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            case MESSAGE_UUID_INTENT:
4731caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh                String address = (String)msg.obj;
47416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (address != null) {
4751caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh                    sendUuidIntent(address);
47616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    makeServiceChannelCallbacks(address);
47716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                }
4781caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh                break;
47912835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            case MESSAGE_DISCOVERABLE_TIMEOUT:
48012835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                int mode = msg.arg1;
4818c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh                if (isEnabledInternal()) {
48212835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                    // TODO: Switch back to the previous scan mode
48312835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                    // This is ok for now, because we only use
48412835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                    // CONNECTABLE and CONNECTABLE_DISCOVERABLE
48512835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                    setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE, -1);
48612835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                }
48712835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                break;
4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private EnableThread mEnableThread;
4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private class EnableThread extends Thread {
4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final boolean mSaveSetting;
496105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        public EnableThread(boolean saveSetting) {
4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mSaveSetting = saveSetting;
4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void run() {
5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean res = (enableNative() == 0);
5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (res) {
502b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                int retryCount = 2;
503b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                boolean running = false;
504b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                while ((retryCount-- > 0) && !running) {
505b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    mEventLoop.start();
506105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    // it may take a momement for the other thread to do its
507b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    // thing.  Check periodically for a while.
508b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    int pollCount = 5;
509b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    while ((pollCount-- > 0) && !running) {
510b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                        if (mEventLoop.isEventLoopRunning()) {
511b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                            running = true;
512b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                            break;
513b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                        }
514b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                        try {
515b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                            Thread.sleep(100);
516b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                        } catch (InterruptedException e) {}
517b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    }
518b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                }
519b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                if (!running) {
520b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    log("bt EnableThread giving up");
521b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    res = false;
522b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    disableNative();
523b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                }
5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (res) {
528d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                if (!setupNativeDataNative()) {
529d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                    return;
530d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                }
5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mSaveSetting) {
5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    persistBluetoothOnSetting(true);
5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mIsDiscovering = false;
535c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                mBondState.readAutoPairingData();
5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mBondState.loadBondState();
537bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                mHandler.sendMessageDelayed(
538bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                        mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS, 1, -1), 3000);
5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
540105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                // Log bluetooth on to battery stats.
541105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                long ident = Binder.clearCallingIdentity();
542105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                try {
543105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    mBatteryStats.noteBluetoothOn();
544105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                } catch (RemoteException e) {
545105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                } finally {
546105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    Binder.restoreCallingIdentity(ident);
547105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                }
5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
549105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
550105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            mEnableThread = null;
551105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
552105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            setBluetoothState(res ?
553de893f550301a60274e87aa8168225e7a7a42184Nick Pelly                              BluetoothAdapter.STATE_ON :
554de893f550301a60274e87aa8168225e7a7a42184Nick Pelly                              BluetoothAdapter.STATE_OFF);
555105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
556b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            if (res) {
557105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                // Update mode
558d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                String[] propVal = {"Pairable", getProperty("Pairable")};
559d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                mEventLoop.onPropertyChanged(propVal);
560b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            }
561b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project
56244303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey            if (mIsAirplaneSensitive && isAirplaneModeOn() && !mIsAirplaneToggleable) {
5635c43f735d94a538dc273c8f859d1100a7cdd5c71Daisuke Miyakawa                disable(false);
5645c43f735d94a538dc273c8f859d1100a7cdd5c71Daisuke Miyakawa            }
5655c43f735d94a538dc273c8f859d1100a7cdd5c71Daisuke Miyakawa
5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void persistBluetoothOnSetting(boolean bluetoothOn) {
5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long origCallerIdentityToken = Binder.clearCallingIdentity();
5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.BLUETOOTH_ON,
5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                bluetoothOn ? 1 : 0);
5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Binder.restoreCallingIdentity(origCallerIdentityToken);
5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* package */ BondState getBondState() {
5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mBondState;
5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** local cache of bonding state.
5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* we keep our own state to track the intermediate state BONDING, which
5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* bluez does not track.
5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * All addreses must be passed in upper case.
5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public class BondState {
5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final HashMap<String, Integer> mState = new HashMap<String, Integer>();
5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final HashMap<String, Integer> mPinAttempt = new HashMap<String, Integer>();
588c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh
589c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        private static final String AUTO_PAIRING_BLACKLIST =
590c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            "/etc/bluetooth/auto_pairing.conf";
591c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        private static final String DYNAMIC_AUTO_PAIRING_BLACKLIST =
592c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            "/data/misc/bluetooth/dynamic_auto_pairing.conf";
593c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        private ArrayList<String>  mAutoPairingAddressBlacklist;
594c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        private ArrayList<String> mAutoPairingExactNameBlacklist;
595c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        private ArrayList<String> mAutoPairingPartialNameBlacklist;
596c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        // Addresses added to blacklist dynamically based on usage.
597c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        private ArrayList<String> mAutoPairingDynamicAddressBlacklist;
598c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh
599482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh
6002092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        // If this is an outgoing connection, store the address.
6012092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        // There can be only 1 pending outgoing connection at a time,
6022092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        private String mPendingOutgoingBonding;
6032092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
6042092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        private synchronized void setPendingOutgoingBonding(String address) {
6052092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh            mPendingOutgoingBonding = address;
6062092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        }
6072092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
6082092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        public synchronized String getPendingOutgoingBonding() {
6092092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh            return mPendingOutgoingBonding;
6102092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        }
6112092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized void loadBondState() {
613de893f550301a60274e87aa8168225e7a7a42184Nick Pelly            if (mBluetoothState != BluetoothAdapter.STATE_TURNING_ON) {
6149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
6159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
616d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            String []bonds = null;
617b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh            String val = getPropertyInternal("Devices");
618d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            if (val != null) {
619d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                bonds = val.split(",");
620d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            }
6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (bonds == null) {
6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mState.clear();
6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (DBG) log("found " + bonds.length + " bonded devices");
626d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            for (String device : bonds) {
627d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                mState.put(getAddressFromObjectPath(device).toUpperCase(),
628d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                        BluetoothDevice.BOND_BONDED);
6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized void setBondState(String address, int state) {
6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setBondState(address, state, 0);
6349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /** reason is ignored unless state == BOND_NOT_BONDED */
6379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized void setBondState(String address, int state, int reason) {
6389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int oldState = getBondState(address);
6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (oldState == state) {
6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6422092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
6432092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh            // Check if this was an pending outgoing bonding.
6442092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh            // If yes, reset the state.
6452092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh            if (oldState == BluetoothDevice.BOND_BONDING) {
6462092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh                if (address.equals(mPendingOutgoingBonding)) {
6472092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh                    mPendingOutgoingBonding = null;
6482092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh                }
6492092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh            }
6502092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (DBG) log(address + " bond state " + oldState + " -> " + state + " (" +
6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                         reason + ")");
653005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            Intent intent = new Intent(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
654005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
655005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            intent.putExtra(BluetoothDevice.EXTRA_BOND_STATE, state);
656005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            intent.putExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, oldState);
657005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            if (state == BluetoothDevice.BOND_NONE) {
6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (reason <= 0) {
6599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Log.w(TAG, "setBondState() called to unbond device, but reason code is " +
6609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                          "invalid. Overriding reason code with BOND_RESULT_REMOVED");
6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    reason = BluetoothDevice.UNBOND_REASON_REMOVED;
6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
663005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly                intent.putExtra(BluetoothDevice.EXTRA_REASON, reason);
6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mState.remove(address);
6659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mState.put(address, state);
6679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mContext.sendBroadcast(intent, BLUETOOTH_PERM);
6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public boolean isAutoPairingBlacklisted(String address) {
673c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            if (mAutoPairingAddressBlacklist != null) {
674c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                for (String blacklistAddress : mAutoPairingAddressBlacklist) {
675c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    if (address.startsWith(blacklistAddress)) return true;
676c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                }
6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
678482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh
679c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            if (mAutoPairingDynamicAddressBlacklist != null) {
680c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                for (String blacklistAddress: mAutoPairingDynamicAddressBlacklist) {
681c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    if (address.equals(blacklistAddress)) return true;
682c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                }
683c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            }
684482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh            String name = getRemoteName(address);
685482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh            if (name != null) {
686c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                if (mAutoPairingExactNameBlacklist != null) {
687c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    for (String blacklistName : mAutoPairingExactNameBlacklist) {
688c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        if (name.equals(blacklistName)) return true;
689c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    }
690738ed80262aa26128924c51f59ffd49e1163eb8dJaikumar Ganesh                }
691738ed80262aa26128924c51f59ffd49e1163eb8dJaikumar Ganesh
692c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                if (mAutoPairingPartialNameBlacklist != null) {
693c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    for (String blacklistName : mAutoPairingPartialNameBlacklist) {
694c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        if (name.startsWith(blacklistName)) return true;
695c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    }
696482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh                }
697482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh            }
6989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
6999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized int getBondState(String address) {
7029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Integer state = mState.get(address);
7039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (state == null) {
704005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly                return BluetoothDevice.BOND_NONE;
7059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return state.intValue();
7079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
709e5d93b7ed983f98855555d560faf060836f1a52fJaikumar Ganesh        /*package*/ synchronized String[] listInState(int state) {
7109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ArrayList<String> result = new ArrayList<String>(mState.size());
7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (Map.Entry<String, Integer> e : mState.entrySet()) {
7129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (e.getValue().intValue() == state) {
7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    result.add(e.getKey());
7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return result.toArray(new String[result.size()]);
7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized void addAutoPairingFailure(String address) {
720c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            if (mAutoPairingDynamicAddressBlacklist == null) {
721c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                mAutoPairingDynamicAddressBlacklist = new ArrayList<String>();
7229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
723c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh
724c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            updateAutoPairingData(address);
725c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            mAutoPairingDynamicAddressBlacklist.add(address);
7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized boolean isAutoPairingAttemptsInProgress(String address) {
7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return getAttempt(address) != 0;
7309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized void clearPinAttempts(String address) {
7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mPinAttempt.remove(address);
7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized boolean hasAutoPairingFailed(String address) {
737c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            if (mAutoPairingDynamicAddressBlacklist == null) return false;
738c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh
739c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            return mAutoPairingDynamicAddressBlacklist.contains(address);
7409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized int getAttempt(String address) {
7439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Integer attempt = mPinAttempt.get(address);
7449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (attempt == null) {
7459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return 0;
7469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return attempt.intValue();
7489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized void attempt(String address) {
7519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Integer attempt = mPinAttempt.get(address);
7529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int newAttempt;
7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (attempt == null) {
7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                newAttempt = 1;
7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
7569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                newAttempt = attempt.intValue() + 1;
7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mPinAttempt.put(address, new Integer(newAttempt));
7599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
761c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        private void copyAutoPairingData() {
762c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            File file = null;
763c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            FileInputStream in = null;
764c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            FileOutputStream out = null;
765c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            try {
766c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                file = new File(DYNAMIC_AUTO_PAIRING_BLACKLIST);
767c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                if (file.exists()) return;
768c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh
769c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                in = new FileInputStream(AUTO_PAIRING_BLACKLIST);
770c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                out= new FileOutputStream(DYNAMIC_AUTO_PAIRING_BLACKLIST);
771c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh
772c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                byte[] buf = new byte[1024];
773c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                int len;
774c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                while ((len = in.read(buf)) > 0) {
775c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    out.write(buf, 0, len);
776c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                }
777c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            } catch (FileNotFoundException e) {
778c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                log("FileNotFoundException: in copyAutoPairingData");
779c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            } catch (IOException e) {
780c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                log("IOException: in copyAutoPairingData");
781c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            } finally {
782c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                 try {
783c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                     if (in != null) in.close();
784c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                     if (out != null) out.close();
785c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                 } catch (IOException e) {}
786c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            }
787c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        }
788c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh
789c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        public void readAutoPairingData() {
790c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            if (mAutoPairingAddressBlacklist != null) return;
791c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            copyAutoPairingData();
792c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            FileInputStream fstream = null;
793c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            try {
794c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                fstream = new FileInputStream(DYNAMIC_AUTO_PAIRING_BLACKLIST);
795c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                DataInputStream in = new DataInputStream(fstream);
796c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                BufferedReader file = new BufferedReader(new InputStreamReader(in));
797c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                String line;
798c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                while((line = file.readLine()) != null) {
799c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    line = line.trim();
800c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    if (line.length() == 0 || line.startsWith("//")) continue;
801c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    String[] value = line.split("=");
802c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    if (value != null && value.length == 2) {
803c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        String[] val = value[1].split(",");
804c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        if (value[0].equalsIgnoreCase("AddressBlacklist")) {
805c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                            mAutoPairingAddressBlacklist =
806c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                                new ArrayList<String>(Arrays.asList(val));
807c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        } else if (value[0].equalsIgnoreCase("ExactNameBlacklist")) {
808c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                            mAutoPairingExactNameBlacklist =
809c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                                new ArrayList<String>(Arrays.asList(val));
810c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        } else if (value[0].equalsIgnoreCase("PartialNameBlacklist")) {
811c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                            mAutoPairingPartialNameBlacklist =
812c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                                new ArrayList<String>(Arrays.asList(val));
813c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        } else if (value[0].equalsIgnoreCase("DynamicAddressBlacklist")) {
814c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                            mAutoPairingDynamicAddressBlacklist =
815c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                                new ArrayList<String>(Arrays.asList(val));
816c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        } else {
817c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                            Log.e(TAG, "Error parsing Auto pairing blacklist file");
818c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        }
819c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    }
820c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                }
821c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            } catch (FileNotFoundException e) {
822c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                log("FileNotFoundException: readAutoPairingData" + e.toString());
823c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            } catch (IOException e) {
824c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                log("IOException: readAutoPairingData" + e.toString());
825c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            } finally {
826c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                if (fstream != null) {
827c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    try {
828c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        fstream.close();
829c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    } catch (IOException e) {
830c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        // Ignore
831c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    }
832c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                }
833c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            }
834c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        }
835c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh
836c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        // This function adds a bluetooth address to the auto pairing blacklis
837c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        // file. These addresses are added to DynamicAddressBlacklistSection
838c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        private void updateAutoPairingData(String address) {
839c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            BufferedWriter out = null;
840c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            try {
841c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                out = new BufferedWriter(new FileWriter(DYNAMIC_AUTO_PAIRING_BLACKLIST, true));
842c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                StringBuilder str = new StringBuilder();
843c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                if (mAutoPairingDynamicAddressBlacklist.size() == 0) {
844c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    str.append("DynamicAddressBlacklist=");
845c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                }
846c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                str.append(address);
847c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                str.append(",");
848c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                out.write(str.toString());
849c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            } catch (FileNotFoundException e) {
850c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                log("FileNotFoundException: updateAutoPairingData" + e.toString());
851c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            } catch (IOException e) {
852c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                log("IOException: updateAutoPairingData" + e.toString());
853c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            } finally {
854c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                if (out != null) {
855c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    try {
856c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        out.close();
857c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    } catch (IOException e) {
858c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        // Ignore
859c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    }
860c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                }
861c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            }
862c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        }
8639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static String toBondStateString(int bondState) {
8669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        switch (bondState) {
867005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        case BluetoothDevice.BOND_NONE:
8689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "not bonded";
8699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case BluetoothDevice.BOND_BONDING:
8709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "bonding";
8719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case BluetoothDevice.BOND_BONDED:
8729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "bonded";
8739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        default:
8749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "??????";
8759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8789519ce75f15ba287a641166c1b7ed10f2aa73f74Jaikumar Ganesh    /*package*/ synchronized boolean isAdapterPropertiesEmpty() {
8799519ce75f15ba287a641166c1b7ed10f2aa73f74Jaikumar Ganesh        return mAdapterProperties.isEmpty();
8809519ce75f15ba287a641166c1b7ed10f2aa73f74Jaikumar Ganesh    }
8819519ce75f15ba287a641166c1b7ed10f2aa73f74Jaikumar Ganesh
882d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /*package*/synchronized void getAllProperties() {
8838c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
8849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
885bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mAdapterProperties.clear();
886d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
887d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String properties[] = (String [])getAdapterPropertiesNative();
888d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        // The String Array consists of key-value pairs.
889d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (properties == null) {
890d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            Log.e(TAG, "*Error*: GetAdapterProperties returned NULL");
891d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return;
892d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
893d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
8948bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh        for (int i = 0; i < properties.length; i++) {
8958bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            String name = properties[i];
896efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh            String newValue = null;
8978bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            int len;
8988bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            if (name == null) {
8998bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                Log.e(TAG, "Error:Adapter Property at index" + i + "is null");
9008bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                continue;
9018bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            }
9028bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            if (name.equals("Devices")) {
903efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                StringBuilder str = new StringBuilder();
9048bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                len = Integer.valueOf(properties[++i]);
9058bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                for (int j = 0; j < len; j++) {
906efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                    str.append(properties[++i]);
907efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                    str.append(",");
908efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                }
909efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                if (len > 0) {
910efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                    newValue = str.toString();
9118bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                }
9128bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            } else {
9138bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                newValue = properties[++i];
9148bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            }
915bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            mAdapterProperties.put(name, newValue);
916d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
917d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
918d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        // Add adapter object path property.
919d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String adapterPath = getAdapterPathNative();
920d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (adapterPath != null)
921bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            mAdapterProperties.put("ObjectPath", adapterPath + "/dev_");
9229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
924d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ synchronized void setProperty(String name, String value) {
925bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mAdapterProperties.put(name, value);
9269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean setName(String name) {
9299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
9309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
9319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (name == null) {
9329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
9339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
934d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setPropertyString("Name", name);
9359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
937d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    //TODO(): setPropertyString, setPropertyInteger, setPropertyBoolean
938d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    // Either have a single property function with Object as the parameter
939d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    // or have a function for each property and then obfuscate in the JNI layer.
940d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    // The following looks dirty.
941d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private boolean setPropertyString(String key, String value) {
9429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
9438c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
944d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setAdapterPropertyStringNative(key, value);
9459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
947d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private boolean setPropertyInteger(String key, int value) {
948d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
9498c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
950d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setAdapterPropertyIntegerNative(key, value);
951d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
9529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
953d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private boolean setPropertyBoolean(String key, boolean value) {
954d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
9558c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
956d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setAdapterPropertyBooleanNative(key, value ? 1 : 0);
9579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
959d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /**
960d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Set the discoverability window for the device.  A timeout of zero
961d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * makes the device permanently discoverable (if the device is
962d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * discoverable).  Setting the timeout to a nonzero value does not make
963d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * a device discoverable; you need to call setMode() to make the device
964d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * explicitly discoverable.
965d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     *
966d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * @param timeout_s The discoverable timeout in seconds.
967d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     */
968d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized boolean setDiscoverableTimeout(int timeout) {
9699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
9709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
971d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setPropertyInteger("DiscoverableTimeout", timeout);
9729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
97412835478ee687a493d1b5882e67b6725bd539c26Nick Pelly    public synchronized boolean setScanMode(int mode, int duration) {
97518b1e79a123b979d25bfa5d0b0ee5d0382dbd64bNick Pelly        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS,
97618b1e79a123b979d25bfa5d0b0ee5d0382dbd64bNick Pelly                                                "Need WRITE_SECURE_SETTINGS permission");
977de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        boolean pairable = false;
978de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        boolean discoverable = false;
97912835478ee687a493d1b5882e67b6725bd539c26Nick Pelly
980de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        switch (mode) {
981de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.SCAN_MODE_NONE:
98212835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            mHandler.removeMessages(MESSAGE_DISCOVERABLE_TIMEOUT);
983d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            pairable = false;
984d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            discoverable = false;
985de893f550301a60274e87aa8168225e7a7a42184Nick Pelly            break;
986de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
98712835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            mHandler.removeMessages(MESSAGE_DISCOVERABLE_TIMEOUT);
988d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            pairable = true;
989d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            discoverable = false;
990005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            break;
991de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
99212835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            mHandler.removeMessages(MESSAGE_DISCOVERABLE_TIMEOUT);
993d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            pairable = true;
994d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            discoverable = true;
99512835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            Message msg = mHandler.obtainMessage(MESSAGE_DISCOVERABLE_TIMEOUT);
99612835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            mHandler.sendMessageDelayed(msg, duration * 1000);
99712835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            if (DBG) Log.d(TAG, "BT Discoverable for " + duration + " seconds");
998005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            break;
999de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        default:
1000de893f550301a60274e87aa8168225e7a7a42184Nick Pelly            Log.w(TAG, "Requested invalid scan mode " + mode);
1001de893f550301a60274e87aa8168225e7a7a42184Nick Pelly            return false;
1002d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
1003d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        setPropertyBoolean("Pairable", pairable);
1004d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        setPropertyBoolean("Discoverable", discoverable);
10059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1006d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return true;
10079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1009b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh    /*package*/ synchronized String getProperty(String name) {
1010b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh        if (!isEnabledInternal()) return null;
1011b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh        return getPropertyInternal(name);
1012b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh    }
1013b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh
1014b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh    /*package*/ synchronized String getPropertyInternal(String name) {
1015bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        if (!mAdapterProperties.isEmpty())
1016bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            return mAdapterProperties.get(name);
1017d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        getAllProperties();
1018bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        return mAdapterProperties.get(name);
10199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1021d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized String getAddress() {
1022d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1023d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return getProperty("Address");
10249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1026d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized String getName() {
10279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1028d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return getProperty("Name");
10299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1032d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Returns the user-friendly name of a remote device.  This value is
1033d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * returned from our local cache, which is updated when onPropertyChange
1034d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * event is received.
1035d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Do not expect to retrieve the updated remote name immediately after
1036d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * changing the name on the remote device.
10379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1038d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * @param address Bluetooth address of remote device.
1039d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     *
1040d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * @return The user-friendly name of the specified remote device.
10419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1042d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized String getRemoteName(String address) {
1043d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1044005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1045d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return null;
1046d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
104755929a958bf0e482c8e4d7df3dd75957f1e9d871Jaikumar Ganesh        return getRemoteDeviceProperty(address, "Name");
10489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
10519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Get the discoverability window for the device.  A timeout of zero
10529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * means that the device is permanently discoverable (if the device is
10539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * in the discoverable mode).
10549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
10559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The discoverability window of the device, in seconds.  A negative
10569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         value indicates an error.
10579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
10589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized int getDiscoverableTimeout() {
10599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1060d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String timeout = getProperty("DiscoverableTimeout");
1061d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (timeout != null)
1062d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh           return Integer.valueOf(timeout);
1063d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        else
1064d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return -1;
10659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized int getScanMode() {
10689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
10698c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal())
1070de893f550301a60274e87aa8168225e7a7a42184Nick Pelly            return BluetoothAdapter.SCAN_MODE_NONE;
1071d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1072d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        boolean pairable = getProperty("Pairable").equals("true");
1073d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        boolean discoverable = getProperty("Discoverable").equals("true");
1074d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return bluezStringToScanMode (pairable, discoverable);
10759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1077d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized boolean startDiscovery() {
10789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
10799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
10808c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
10818c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1082d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return startDiscoveryNative();
10839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1085d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized boolean cancelDiscovery() {
10869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
10879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
10888c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
10898c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1090d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return stopDiscoveryNative();
1091d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
1092d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1093d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized boolean isDiscovering() {
1094d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1095d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return mIsDiscovering;
1096d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
1097d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1098d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ void setIsDiscovering(boolean isDiscovering) {
1099d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mIsDiscovering = isDiscovering;
11009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean createBond(String address) {
11039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
11049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
11058c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
11068c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1107005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
11089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
11099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        address = address.toUpperCase();
11119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11122092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        if (mBondState.getPendingOutgoingBonding() != null) {
11139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            log("Ignoring createBond(): another device is bonding");
11149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // a different device is currently bonding, fail
11159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
11169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Check for bond state only if we are not performing auto
11199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // pairing exponential back-off attempts.
11209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mBondState.isAutoPairingAttemptsInProgress(address) &&
1121005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly                mBondState.getBondState(address) != BluetoothDevice.BOND_NONE) {
11229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            log("Ignoring createBond(): this device is already bonding or bonded");
11239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
11249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11263fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        if (address.equals(mDockAddress)) {
11273fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            if (!writeDockPin()) {
11283fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                log("Error while writing Pin for the dock");
11293fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                return false;
11303fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            }
11313fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        }
11323fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
1133d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (!createPairedDeviceNative(address, 60000 /* 1 minute */)) {
11349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
11359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11372092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        mBondState.setPendingOutgoingBonding(address);
11389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mBondState.setBondState(address, BluetoothDevice.BOND_BONDING);
11392092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
11409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
11419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean cancelBondProcess(String address) {
11449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
11459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
11468c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
11478c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1148005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
11499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
11509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        address = address.toUpperCase();
11529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mBondState.getBondState(address) != BluetoothDevice.BOND_BONDING) {
11539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
11549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1156005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        mBondState.setBondState(address, BluetoothDevice.BOND_NONE,
11579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
1158d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        cancelDeviceCreationNative(address);
11599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
11609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean removeBond(String address) {
11639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
11649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
11658c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
11668c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1167005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
11689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
11699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1170d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return removeDeviceNative(getObjectPathFromAddress(address));
11719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized String[] listBonds() {
11749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
11759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mBondState.listInState(BluetoothDevice.BOND_BONDED);
11769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized int getBondState(String address) {
11799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1180005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1181b24e11baac589fe16426f2d243b460ab84991c7bNick Pelly            return BluetoothDevice.ERROR;
11829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mBondState.getBondState(address.toUpperCase());
11849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11863fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    public synchronized boolean isBluetoothDock(String address) {
11876e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh        SharedPreferences sp = mContext.getSharedPreferences(SHARED_PREFERENCES_NAME,
11886e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                mContext.MODE_PRIVATE);
11896e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh
11906e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh        return sp.contains(SHARED_PREFERENCE_DOCK_ADDRESS + address);
11913fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    }
11923fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
11939488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh    /*package*/ boolean isRemoteDeviceInCache(String address) {
1194bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        return (mDeviceProperties.get(address) != null);
11959488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh    }
11969488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh
11979488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh    /*package*/ String[] getRemoteDeviceProperties(String address) {
11988c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return null;
11998c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
12009488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh        String objectPath = getObjectPathFromAddress(address);
12019488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh        return (String [])getDevicePropertiesNative(objectPath);
12029488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh    }
12039488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh
1204d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /*package*/ synchronized String getRemoteDeviceProperty(String address, String property) {
1205bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        Map<String, String> properties = mDeviceProperties.get(address);
1206d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (properties != null) {
1207d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return properties.get(property);
1208d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        } else {
1209d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            // Query for remote device properties, again.
1210d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            // We will need to reload the cache when we switch Bluetooth on / off
1211d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            // or if we crash.
121210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            if (updateRemoteDevicePropertiesCache(address))
1213d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                return getRemoteDeviceProperty(address, property);
12149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1215d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        Log.e(TAG, "getRemoteDeviceProperty: " + property + "not present:" + address);
1216d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return null;
12179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
121910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh    /* package */ synchronized boolean updateRemoteDevicePropertiesCache(String address) {
122010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        String[] propValues = getRemoteDeviceProperties(address);
122110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        if (propValues != null) {
122210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            addRemoteDeviceProperties(address, propValues);
122310eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            return true;
122410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        }
122510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        return false;
122610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh    }
122710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
1228d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ synchronized void addRemoteDeviceProperties(String address, String[] properties) {
1229395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh        /*
1230395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh         * We get a DeviceFound signal every time RSSI changes or name changes.
1231395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh         * Don't create a new Map object every time */
1232bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        Map<String, String> propertyValues = mDeviceProperties.get(address);
1233efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh        if (propertyValues == null) {
1234395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh            propertyValues = new HashMap<String, String>();
1235395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh        }
1236395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh
12378bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh        for (int i = 0; i < properties.length; i++) {
12388bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            String name = properties[i];
1239efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh            String newValue = null;
12408bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            int len;
12418bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            if (name == null) {
12428bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                Log.e(TAG, "Error: Remote Device Property at index" + i + "is null");
12438bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                continue;
12448bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            }
12458bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            if (name.equals("UUIDs") || name.equals("Nodes")) {
1246efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                StringBuilder str = new StringBuilder();
12478bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                len = Integer.valueOf(properties[++i]);
12488bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                for (int j = 0; j < len; j++) {
1249efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                    str.append(properties[++i]);
1250efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                    str.append(",");
1251efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                }
1252efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                if (len > 0) {
1253efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                    newValue = str.toString();
12548bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                }
1255d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            } else {
12568bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                newValue = properties[++i];
1257d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            }
1258efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh
12598bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            propertyValues.put(name, newValue);
12609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1261bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mDeviceProperties.put(address, propertyValues);
126210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
126310eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        // We have added a new remote device or updated its properties.
126410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        // Also update the serviceChannel cache.
126510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        updateDeviceServiceChannelCache(address);
12669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1268d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ void removeRemoteDeviceProperties(String address) {
1269bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mDeviceProperties.remove(address);
12709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1272d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ synchronized void setRemoteDeviceProperty(String address, String name,
1273d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                                                              String value) {
1274bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        Map <String, String> propVal = mDeviceProperties.get(address);
1275d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (propVal != null) {
1276d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            propVal.put(name, value);
1277bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            mDeviceProperties.put(address, propVal);
1278d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        } else {
1279d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            Log.e(TAG, "setRemoteDeviceProperty for a device not in cache:" + address);
12809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1284efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * Sets the remote device trust state.
1285efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     *
1286efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * @return boolean to indicate operation success or fail
1287efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     */
1288efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    public synchronized boolean setTrust(String address, boolean value) {
1289005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1290e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly            mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1291e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly                    "Need BLUETOOTH_ADMIN permission");
1292efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            return false;
1293efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        }
1294efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue
12958c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
12968c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1297efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        return setDevicePropertyBooleanNative(getObjectPathFromAddress(address), "Trusted",
1298efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue                value ? 1 : 0);
1299efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    }
1300efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue
1301efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    /**
1302efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * Gets the remote device trust state as boolean.
1303efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * Note: this value may be
1304efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * retrieved from cache if we retrieved the data before *
1305efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     *
1306efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * @return boolean to indicate trust or untrust state
1307efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     */
1308efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    public synchronized boolean getTrustState(String address) {
1309005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1310efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1311efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            return false;
1312efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        }
1313efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue
1314efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        String val = getRemoteDeviceProperty(address, "Trusted");
1315efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        if (val == null) {
1316efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            return false;
1317efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        } else {
1318efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            return val.equals("true") ? true : false;
1319efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        }
1320efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    }
1321efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue
1322efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    /**
1323d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Gets the remote major, minor classes encoded as a 32-bit
13249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * integer.
13259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
13269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Note: this value is retrieved from cache, because we get it during
13279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *       remote-device discovery.
13289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
13299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return 32-bit integer encoding the remote major, minor, and service
13309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         classes.
13319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
13329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized int getRemoteClass(String address) {
1333005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1334ea600ccfb7568f60377c4abc85f56c80af7fdbfcNick Pelly            mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1335ea600ccfb7568f60377c4abc85f56c80af7fdbfcNick Pelly            return BluetoothClass.ERROR;
13369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1337d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String val = getRemoteDeviceProperty(address, "Class");
1338d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (val == null)
1339d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return BluetoothClass.ERROR;
1340d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        else {
1341d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return Integer.valueOf(val);
1342d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
13439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1344d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
13459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1347dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh     * Gets the UUIDs supported by the remote device
13489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1349dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh     * @return array of 128bit ParcelUuids
13509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1351dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh    public synchronized ParcelUuid[] getRemoteUuids(String address) {
13529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1353005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
13549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return null;
13559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13561caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        return getUuidFromCache(address);
13571caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    }
13581caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
13591caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    private ParcelUuid[] getUuidFromCache(String address) {
1360d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String value = getRemoteDeviceProperty(address, "UUIDs");
1361dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        if (value == null) return null;
1362dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh
1363dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        String[] uuidStrings = null;
1364d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        // The UUIDs are stored as a "," separated string.
1365dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        uuidStrings = value.split(",");
1366dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        ParcelUuid[] uuids = new ParcelUuid[uuidStrings.length];
1367dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh
1368dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        for (int i = 0; i < uuidStrings.length; i++) {
1369dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh            uuids[i] = ParcelUuid.fromString(uuidStrings[i]);
1370dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        }
1371d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return uuids;
13729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
137416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    /**
137516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * Connect and fetch new UUID's using SDP.
137616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * The UUID's found are broadcast as intents.
137716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * Optionally takes a uuid and callback to fetch the RFCOMM channel for the
137816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * a given uuid.
137916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * TODO: Don't wait UUID_INTENT_DELAY to broadcast UUID intents on success
138016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * TODO: Don't wait UUID_INTENT_DELAY to handle the failure case for
138116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * callback and broadcast intents.
138216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     */
138316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    public synchronized boolean fetchRemoteUuids(String address, ParcelUuid uuid,
138416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            IBluetoothCallback callback) {
13851caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
13868c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
13878c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
13881caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
13891caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            return false;
13901caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        }
13911caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
139216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        RemoteService service = new RemoteService(address, uuid);
139316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        if (uuid != null && mUuidCallbackTracker.get(service) != null) {
139416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            // An SDP query for this address & uuid is already in progress
139516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            // Do not add this callback for the uuid
139616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            return false;
139716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
139816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
13991caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        if (mUuidIntentTracker.contains(address)) {
14001caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            // An SDP query for this address is already in progress
140116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            // Add this uuid onto the in-progress SDP query
140216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (uuid != null) {
140316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                mUuidCallbackTracker.put(new RemoteService(address, uuid), callback);
140416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
14051caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            return true;
14061caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        }
14071caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
14081caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        boolean ret;
14090e09030977aea8b40fd177139528d4b5637c9771Jaikumar Ganesh        // Just do the SDP if the device is already  created and UUIDs are not
14100e09030977aea8b40fd177139528d4b5637c9771Jaikumar Ganesh        // NULL, else create the device and then do SDP.
14110e09030977aea8b40fd177139528d4b5637c9771Jaikumar Ganesh        if (isRemoteDeviceInCache(address) && getRemoteUuids(address) != null) {
14121caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            String path = getObjectPathFromAddress(address);
14131caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            if (path == null) return false;
14141caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
14151caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            // Use an empty string for the UUID pattern
14161caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            ret = discoverServicesNative(path, "");
14171caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        } else {
14181caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            ret = createDeviceNative(address);
14191caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        }
14201caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
14211caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        mUuidIntentTracker.add(address);
142216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        if (uuid != null) {
142316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            mUuidCallbackTracker.put(new RemoteService(address, uuid), callback);
142416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
14251caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
14261caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        Message message = mHandler.obtainMessage(MESSAGE_UUID_INTENT);
14271caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        message.obj = address;
14281caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        mHandler.sendMessageDelayed(message, UUID_INTENT_DELAY);
14291caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        return ret;
14301caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    }
14311caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
14329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1433d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Gets the rfcomm channel associated with the UUID.
143416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * Pulls records from the cache only.
14359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1436d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * @param address Address of the remote device
1437dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh     * @param uuid ParcelUuid of the service attribute
14389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1439d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * @return rfcomm channel associated with the service attribute
144010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh     *         -1 on error
14419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1442dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh    public int getRemoteServiceChannel(String address, ParcelUuid uuid) {
14439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
14448c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return -1;
14458c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1446005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1447b24e11baac589fe16426f2d243b460ab84991c7bNick Pelly            return BluetoothDevice.ERROR;
14489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
144910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        // Check if we are recovering from a crash.
145010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        if (mDeviceProperties.isEmpty()) {
145110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            if (!updateRemoteDevicePropertiesCache(address))
145210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh                return -1;
145310eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        }
145410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
145510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        Map<ParcelUuid, Integer> value = mDeviceServiceChannelCache.get(address);
145610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        if (value != null && value.containsKey(uuid))
145710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            return value.get(uuid);
145810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        return -1;
14599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean setPin(String address, byte[] pin) {
14629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
14639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
14648c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
14658c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
14669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (pin == null || pin.length <= 0 || pin.length > 16 ||
1467005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            !BluetoothAdapter.checkBluetoothAddress(address)) {
14689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
14699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
14709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        address = address.toUpperCase();
14719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
14729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (data == null) {
14739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.w(TAG, "setPin(" + address + ") called but no native data available, " +
14749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                  "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
14759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                  " or by bluez.\n");
14769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
14779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
14789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // bluez API wants pin as a string
14799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String pinString;
14809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
14819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pinString = new String(pin, "UTF8");
14829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (UnsupportedEncodingException uee) {
14839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.e(TAG, "UTF8 not supported?!?");
14849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
14859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
14869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return setPinNative(address, pinString, data.intValue());
14879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1489b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    public synchronized boolean setPasskey(String address, int passkey) {
1490b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1491b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                                                "Need BLUETOOTH_ADMIN permission");
14928c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
14938c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1494005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (passkey < 0 || passkey > 999999 || !BluetoothAdapter.checkBluetoothAddress(address)) {
1495b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            return false;
1496b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        }
1497b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        address = address.toUpperCase();
1498b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
1499b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        if (data == null) {
1500b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            Log.w(TAG, "setPasskey(" + address + ") called but no native data available, " +
1501b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                  "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
1502b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                  " or by bluez.\n");
1503b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            return false;
1504b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        }
1505b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        return setPasskeyNative(address, passkey, data.intValue());
1506b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    }
1507b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh
1508b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    public synchronized boolean setPairingConfirmation(String address, boolean confirm) {
1509b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1510b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                                                "Need BLUETOOTH_ADMIN permission");
15118c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
15128c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1513b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        address = address.toUpperCase();
1514b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
1515b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        if (data == null) {
1516b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            Log.w(TAG, "setPasskey(" + address + ") called but no native data available, " +
1517b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                  "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
1518b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                  " or by bluez.\n");
1519b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            return false;
1520b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        }
1521b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        return setPairingConfirmationNative(address, confirm, data.intValue());
1522b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    }
1523b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh
1524b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    public synchronized boolean cancelPairingUserInput(String address) {
15259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
15269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
15278c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
15288c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1529005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
15309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
15319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1532005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        mBondState.setBondState(address, BluetoothDevice.BOND_NONE,
1533397d8f4f4829a45f4fe7a672cc395466bbc0f442Jaikumar Ganesh                BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
15349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        address = address.toUpperCase();
15359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
15369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (data == null) {
1537b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            Log.w(TAG, "cancelUserInputNative(" + address + ") called but no native data " +
1538b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                "available, ignoring. Maybe the PasskeyAgent Request was already cancelled " +
1539b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                "by the remote or by bluez.\n");
15409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
15419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1542b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        return cancelPairingUserInputNative(address, data.intValue());
15439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
15449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15458c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh    /*package*/ void updateDeviceServiceChannelCache(String address) {
154610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        ParcelUuid[] deviceUuids = getRemoteUuids(address);
154710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        // We are storing the rfcomm channel numbers only for the uuids
154810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        // we are interested in.
154910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        int channel;
155016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        if (DBG) log("updateDeviceServiceChannelCache(" + address + ")");
155116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
155216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        ArrayList<ParcelUuid> applicationUuids = new ArrayList();
155316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
155416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        synchronized (this) {
155516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            for (RemoteService service : mUuidCallbackTracker.keySet()) {
155616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (service.address.equals(address)) {
155716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    applicationUuids.add(service.uuid);
155816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                }
155916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
156016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
156110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
156210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        Map <ParcelUuid, Integer> value = new HashMap<ParcelUuid, Integer>();
156316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
156416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        // Retrieve RFCOMM channel for default uuids
156516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        for (ParcelUuid uuid : RFCOMM_UUIDS) {
156610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            if (BluetoothUuid.isUuidPresent(deviceUuids, uuid)) {
156716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                channel = getDeviceServiceChannelNative(getObjectPathFromAddress(address),
156816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        uuid.toString(), 0x0004);
156916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (DBG) log("\tuuid(system): " + uuid + " " + channel);
157010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh                value.put(uuid, channel);
157110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            }
157210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        }
157316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        // Retrieve RFCOMM channel for application requested uuids
157416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        for (ParcelUuid uuid : applicationUuids) {
157516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (BluetoothUuid.isUuidPresent(deviceUuids, uuid)) {
157616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                channel = getDeviceServiceChannelNative(getObjectPathFromAddress(address),
157716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        uuid.toString(), 0x0004);
157816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (DBG) log("\tuuid(application): " + uuid + " " + channel);
157916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                value.put(uuid, channel);
158016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
158116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
158216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
158316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        synchronized (this) {
158416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            // Make application callbacks
158516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            for (Iterator<RemoteService> iter = mUuidCallbackTracker.keySet().iterator();
158616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    iter.hasNext();) {
158716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                RemoteService service = iter.next();
158816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (service.address.equals(address)) {
158916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    channel = -1;
159016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    if (value.get(service.uuid) != null) {
159116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        channel = value.get(service.uuid);
159216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    }
159316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    if (channel != -1) {
159416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        if (DBG) log("Making callback for " + service.uuid + " with result " +
159516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                                channel);
159616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        IBluetoothCallback callback = mUuidCallbackTracker.get(service);
159716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        if (callback != null) {
159816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                            try {
159916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                                callback.onRfcommChannelFound(channel);
160016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                            } catch (RemoteException e) {Log.e(TAG, "", e);}
160116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        }
160216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
160316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        iter.remove();
160416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    }
160516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                }
160616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
160716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
160816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            // Update cache
160916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            mDeviceServiceChannelCache.put(address, value);
161016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
161110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh    }
161210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
161324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    /**
161424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     * b is a handle to a Binder instance, so that this service can be notified
161524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     * for Applications that terminate unexpectedly, to clean there service
161624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     * records
161724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     */
161824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    public synchronized int addRfcommServiceRecord(String serviceName, ParcelUuid uuid,
161924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            int channel, IBinder b) {
16208c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
16218c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return -1;
16228c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
162324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (serviceName == null || uuid == null || channel < 1 ||
162424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                channel > BluetoothSocket.MAX_RFCOMM_CHANNEL) {
162524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            return -1;
162624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
162724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (BluetoothUuid.isUuidPresent(BluetoothUuid.RESERVED_UUIDS, uuid)) {
162824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            Log.w(TAG, "Attempted to register a reserved UUID: " + uuid);
162924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            return -1;
163024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
163124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        int handle = addRfcommServiceRecordNative(serviceName,
163224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                uuid.getUuid().getMostSignificantBits(), uuid.getUuid().getLeastSignificantBits(),
163324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                (short)channel);
163424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (DBG) log("new handle " + Integer.toHexString(handle));
163524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (handle == -1) {
163624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            return -1;
163724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
163824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
163924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        int pid = Binder.getCallingPid();
164024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        mServiceRecordToPid.put(new Integer(handle), new Integer(pid));
164124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        try {
164224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            b.linkToDeath(new Reaper(handle, pid), 0);
164324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        } catch (RemoteException e) {}
164424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        return handle;
164524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    }
164624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
164724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    public void removeServiceRecord(int handle) {
164824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
164924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                                                "Need BLUETOOTH permission");
165024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        checkAndRemoveRecord(handle, Binder.getCallingPid());
165124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    }
165224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
165324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private synchronized void checkAndRemoveRecord(int handle, int pid) {
165424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        Integer handleInt = new Integer(handle);
165524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        Integer owner = mServiceRecordToPid.get(handleInt);
165624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (owner != null && pid == owner.intValue()) {
165724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            if (DBG) log("Removing service record " + Integer.toHexString(handle) + " for pid " +
165824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                    pid);
165924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            mServiceRecordToPid.remove(handleInt);
166024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            removeServiceRecordNative(handle);
166124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
166224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    }
166324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
166424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private class Reaper implements IBinder.DeathRecipient {
166524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        int pid;
166624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        int handle;
166724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        Reaper(int handle, int pid) {
166824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            this.pid = pid;
166924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            this.handle = handle;
167024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
167124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        public void binderDied() {
167224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            synchronized (BluetoothService.this) {
167324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                if (DBG) log("Tracked app " + pid + " died");
167424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                checkAndRemoveRecord(handle, pid);
167524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            }
167624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
167724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    }
167824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
16799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
16809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
16819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onReceive(Context context, Intent intent) {
16826e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh            if (intent == null) return;
16836e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh
16849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String action = intent.getAction();
16859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
16869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ContentResolver resolver = context.getContentResolver();
16879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Query the airplane mode from Settings.System just to make sure that
16889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // some random app is not sending this intent and disabling bluetooth
16899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                boolean enabled = !isAirplaneModeOn();
16909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // If bluetooth is currently expected to be on, then enable or disable bluetooth
16919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (Settings.Secure.getInt(resolver, Settings.Secure.BLUETOOTH_ON, 0) > 0) {
16929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (enabled) {
1693105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                        enable(false);
16949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } else {
16959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        disable(false);
16969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
16979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
16986e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh            } else if (Intent.ACTION_DOCK_EVENT.equals(action)) {
16996e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                int state = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
17006e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                        Intent.EXTRA_DOCK_STATE_UNDOCKED);
17016e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                if (DBG) Log.v(TAG, "Received ACTION_DOCK_EVENT with State:" + state);
17026e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                if (state == Intent.EXTRA_DOCK_STATE_UNDOCKED) {
17036e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                    mDockAddress = null;
17046e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                    mDockPin = null;
17056e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                } else {
17066e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                    SharedPreferences.Editor editor =
17076e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                        mContext.getSharedPreferences(SHARED_PREFERENCES_NAME,
17086e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                                mContext.MODE_PRIVATE).edit();
17096e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                    editor.putBoolean(SHARED_PREFERENCE_DOCK_ADDRESS + mDockAddress, true);
17106e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                    editor.commit();
17116e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                }
17129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
17139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
17149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
17159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17166e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh    private void registerForAirplaneMode(IntentFilter filter) {
171744303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        final ContentResolver resolver = mContext.getContentResolver();
171844303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        final String airplaneModeRadios = Settings.System.getString(resolver,
17199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Settings.System.AIRPLANE_MODE_RADIOS);
172044303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        final String toggleableRadios = Settings.System.getString(resolver,
172144303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey                Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
172244303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey
172344303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        mIsAirplaneSensitive = airplaneModeRadios == null ? true :
172444303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey                airplaneModeRadios.contains(Settings.System.RADIO_BLUETOOTH);
172544303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        mIsAirplaneToggleable = toggleableRadios == null ? false :
172644303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey                toggleableRadios.contains(Settings.System.RADIO_BLUETOOTH);
172744303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey
17289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mIsAirplaneSensitive) {
17296e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh            filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
17309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
17319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
17329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* Returns true if airplane mode is currently on */
17349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final boolean isAirplaneModeOn() {
17359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return Settings.System.getInt(mContext.getContentResolver(),
17369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Settings.System.AIRPLANE_MODE_ON, 0) == 1;
17379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
17389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17391caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    /* Broadcast the Uuid intent */
17401caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    /*package*/ synchronized void sendUuidIntent(String address) {
17416179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh        ParcelUuid[] uuid = getUuidFromCache(address);
17426179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh        Intent intent = new Intent(BluetoothDevice.ACTION_UUID);
17432d3b98d868cda30535505b2a2fba47aa1c9c052bJaikumar Ganesh        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
17446179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh        intent.putExtra(BluetoothDevice.EXTRA_UUID, uuid);
17456179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh        mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
17461caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
17476179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh        if (mUuidIntentTracker.contains(address))
17481caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            mUuidIntentTracker.remove(address);
174916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
175016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    }
175116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
175216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    /*package*/ synchronized void makeServiceChannelCallbacks(String address) {
175316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        for (Iterator<RemoteService> iter = mUuidCallbackTracker.keySet().iterator();
175416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                iter.hasNext();) {
175516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            RemoteService service = iter.next();
175616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (service.address.equals(address)) {
175716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (DBG) log("Cleaning up failed UUID channel lookup: " + service.address +
175816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        " " + service.uuid);
175916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                IBluetoothCallback callback = mUuidCallbackTracker.get(service);
176016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (callback != null) {
176116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    try {
176216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        callback.onRfcommChannelFound(-1);
176316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    } catch (RemoteException e) {Log.e(TAG, "", e);}
176416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                }
176516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
176616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                iter.remove();
176716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
176816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
17691caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    }
17701caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
17719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
17729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1773105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        switch(mBluetoothState) {
1774de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_OFF:
177524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            pw.println("Bluetooth OFF\n");
1776105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return;
1777de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_TURNING_ON:
177824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            pw.println("Bluetooth TURNING ON\n");
1779105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return;
1780de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_TURNING_OFF:
178124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            pw.println("Bluetooth TURNING OFF\n");
1782105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return;
1783de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_ON:
178424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            pw.println("Bluetooth ON\n");
1785105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
1786105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
178724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("mIsAirplaneSensitive = " + mIsAirplaneSensitive);
178844303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        pw.println("mIsAirplaneToggleable = " + mIsAirplaneToggleable);
178924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
179024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("Local address = " + getAddress());
179124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("Local name = " + getName());
179224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("isDiscovering() = " + isDiscovering());
1793105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
1794105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        BluetoothHeadset headset = new BluetoothHeadset(mContext, null);
1795105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
1796105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        pw.println("\n--Known devices--");
1797bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        for (String address : mDeviceProperties.keySet()) {
17981eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly            int bondState = mBondState.getBondState(address);
1799105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            pw.printf("%s %10s (%d) %s\n", address,
18001eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly                       toBondStateString(bondState),
1801105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                       mBondState.getAttempt(address),
1802105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                       getRemoteName(address));
180324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
180424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            Map<ParcelUuid, Integer> uuidChannels = mDeviceServiceChannelCache.get(address);
180524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            if (uuidChannels == null) {
180624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                pw.println("\tuuids = null");
180724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            } else {
180824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                for (ParcelUuid uuid : uuidChannels.keySet()) {
180924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                    Integer channel = uuidChannels.get(uuid);
181024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                    if (channel == null) {
181124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                        pw.println("\t" + uuid);
181224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                    } else {
181324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                        pw.println("\t" + uuid + " RFCOMM channel = " + channel);
18141eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly                    }
18151eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly                }
18161eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly            }
181716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            for (RemoteService service : mUuidCallbackTracker.keySet()) {
181816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (service.address.equals(address)) {
181916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    pw.println("\tPENDING CALLBACK: " + service.uuid);
182016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                }
182116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
1822105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
1823105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
1824d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String value = getProperty("Devices");
18251eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly        String[] devicesObjectPath = null;
1826d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (value != null) {
1827d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            devicesObjectPath = value.split(",");
1828d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
1829105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        pw.println("\n--ACL connected devices--");
183024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (devicesObjectPath != null) {
183124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            for (String device : devicesObjectPath) {
183224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                pw.println(getAddressFromObjectPath(device));
183324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            }
1834105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
1835105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
1836105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Rather not do this from here, but no-where else and I need this
1837105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // dump
1838105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        pw.println("\n--Headset Service--");
1839105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        switch (headset.getState()) {
1840105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        case BluetoothHeadset.STATE_DISCONNECTED:
1841105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            pw.println("getState() = STATE_DISCONNECTED");
1842105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            break;
1843105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        case BluetoothHeadset.STATE_CONNECTING:
1844105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            pw.println("getState() = STATE_CONNECTING");
1845105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            break;
1846105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        case BluetoothHeadset.STATE_CONNECTED:
1847105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            pw.println("getState() = STATE_CONNECTED");
1848105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            break;
1849105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        case BluetoothHeadset.STATE_ERROR:
1850105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            pw.println("getState() = STATE_ERROR");
1851105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            break;
1852105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
18536c901db72dbaf57d8fdf26adae6721de14ecae22Nick Pelly
185424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("\ngetCurrentHeadset() = " + headset.getCurrentHeadset());
185524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("getBatteryUsageHint() = " + headset.getBatteryUsageHint());
1856105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        headset.close();
185724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("\n--Application Service Records--");
185824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        for (Integer handle : mServiceRecordToPid.keySet()) {
185924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            Integer pid = mServiceRecordToPid.get(handle);
186024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            pw.println("\tpid " + pid + " handle " + Integer.toHexString(handle));
186124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
18629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
18639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1864d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ static int bluezStringToScanMode(boolean pairable, boolean discoverable) {
1865d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (pairable && discoverable)
1866bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            return BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE;
1867d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        else if (pairable && !discoverable)
1868bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            return BluetoothAdapter.SCAN_MODE_CONNECTABLE;
1869d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        else
1870bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            return BluetoothAdapter.SCAN_MODE_NONE;
18719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
18729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* package */ static String scanModeToBluezString(int mode) {
18749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        switch (mode) {
1875bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        case BluetoothAdapter.SCAN_MODE_NONE:
18769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "off";
1877bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
18789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "connectable";
1879bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
18809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "discoverable";
18819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
18829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return null;
18839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
18849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1885d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /*package*/ String getAddressFromObjectPath(String objectPath) {
1886b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh        String adapterObjectPath = getPropertyInternal("ObjectPath");
1887d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (adapterObjectPath == null || objectPath == null) {
1888d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            Log.e(TAG, "getAddressFromObjectPath: AdpaterObjectPath:" + adapterObjectPath +
1889d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                    "  or deviceObjectPath:" + objectPath + " is null");
1890d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return null;
1891d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
1892d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (!objectPath.startsWith(adapterObjectPath)) {
1893d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            Log.e(TAG, "getAddressFromObjectPath: AdpaterObjectPath:" + adapterObjectPath +
1894d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                    "  is not a prefix of deviceObjectPath:" + objectPath +
1895d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                    "bluetoothd crashed ?");
1896d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return null;
1897d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
1898d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String address = objectPath.substring(adapterObjectPath.length());
1899d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (address != null) return address.replace('_', ':');
1900d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1901d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        Log.e(TAG, "getAddressFromObjectPath: Address being returned is null");
1902d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return null;
1903d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
1904d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1905d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /*package*/ String getObjectPathFromAddress(String address) {
1906b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh        String path = getPropertyInternal("ObjectPath");
1907d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (path == null) {
1908d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            Log.e(TAG, "Error: Object Path is null");
1909d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return null;
1910d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
1911d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        path = path + address.replace(":", "_");
1912d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return path;
1913d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
1914d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1915b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh    /*package */ void setLinkTimeout(String address, int num_slots) {
1916b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh        String path = getObjectPathFromAddress(address);
1917b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh        boolean result = setLinkTimeoutNative(path, num_slots);
1918b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh
1919b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh        if (!result) log("Set Link Timeout to:" + num_slots + " slots failed");
1920b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh    }
1921b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh
19229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static void log(String msg) {
19239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Log.d(TAG, msg);
19249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1925d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1926d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native static void classInitNative();
1927d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native void initializeNativeDataNative();
1928d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setupNativeDataNative();
1929d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean tearDownNativeDataNative();
1930d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native void cleanupNativeDataNative();
1931d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native String getAdapterPathNative();
1932d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1933d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native int isEnabledNative();
1934d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native int enableNative();
1935d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native int disableNative();
1936d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1937d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native Object[] getAdapterPropertiesNative();
1938d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native Object[] getDevicePropertiesNative(String objectPath);
1939d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setAdapterPropertyStringNative(String key, String value);
1940d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setAdapterPropertyIntegerNative(String key, int value);
1941d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setAdapterPropertyBooleanNative(String key, int value);
1942d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1943d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean startDiscoveryNative();
1944d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean stopDiscoveryNative();
1945d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1946d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean createPairedDeviceNative(String address, int timeout_ms);
1947d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean cancelDeviceCreationNative(String address);
1948d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean removeDeviceNative(String objectPath);
1949d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native int getDeviceServiceChannelNative(String objectPath, String uuid,
1950d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            int attributeId);
1951d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1952b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    private native boolean cancelPairingUserInputNative(String address, int nativeData);
1953d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setPinNative(String address, String pin, int nativeData);
1954b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    private native boolean setPasskeyNative(String address, int passkey, int nativeData);
1955b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    private native boolean setPairingConfirmationNative(String address, boolean confirm,
1956b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            int nativeData);
195724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private native boolean setDevicePropertyBooleanNative(String objectPath, String key,
195824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            int value);
19591caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    private native boolean createDeviceNative(String address);
196016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    /*package*/ native boolean discoverServicesNative(String objectPath, String pattern);
196110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
196224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private native int addRfcommServiceRecordNative(String name, long uuidMsb, long uuidLsb,
196324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            short channel);
196424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private native boolean removeServiceRecordNative(int handle);
1965b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh    private native boolean setLinkTimeoutNative(String path, int num_slots);
19669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1967