BluetoothService.java revision aef439e6f825c0cb99a2ac08c8207f48b7a9fe10
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;
3110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganeshimport android.bluetooth.BluetoothUuid;
32bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pellyimport android.bluetooth.IBluetooth;
33aef439e6f825c0cb99a2ac08c8207f48b7a9fe10Nick Pellyimport android.os.ParcelUuid;
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.BroadcastReceiver;
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ContentResolver;
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Intent;
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.IntentFilter;
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Binder;
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Handler;
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Message;
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.RemoteException;
43105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Projectimport android.os.ServiceManager;
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemService;
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.Settings;
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log;
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
48d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganeshimport com.android.internal.app.IBatteryStats;
49d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileDescriptor;
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.PrintWriter;
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.UnsupportedEncodingException;
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList;
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Arrays;
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.HashMap;
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Map;
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
58bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pellypublic class BluetoothService extends IBluetooth.Stub {
59bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    private static final String TAG = "BluetoothService";
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final boolean DBG = true;
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mNativeData;
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private BluetoothEventLoop mEventLoop;
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private IntentFilter mIntentFilter;
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mIsAirplaneSensitive;
66105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private int mBluetoothState;
67997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly    private boolean mRestart = false;  // need to call enable() after disable()
68bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    private boolean mIsDiscovering;
69997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly
70bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    private BluetoothAdapter mAdapter;  // constant after init()
71997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly    private final BondState mBondState = new BondState();  // local cache of bondings
72105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private final IBatteryStats mBatteryStats;
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final Context mContext;
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
78105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private static final int MESSAGE_REGISTER_SDP_RECORDS = 1;
79105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private static final int MESSAGE_FINISH_DISABLE = 2;
801caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    private static final int MESSAGE_UUID_INTENT = 3;
8112835478ee687a493d1b5882e67b6725bd539c26Nick Pelly    private static final int MESSAGE_DISCOVERABLE_TIMEOUT = 4;
821caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
831caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    // The timeout used to sent the UUIDs Intent
841caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    // This timeout should be greater than the page timeout
851caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    private static final int UUID_INTENT_DELAY = 6000;
86105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
87bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    private final Map<String, String> mAdapterProperties;
88bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    private final HashMap <String, Map<String, String>> mDeviceProperties;
89d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
9010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh    private final HashMap <String, Map<ParcelUuid, Integer>> mDeviceServiceChannelCache;
911caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    private final ArrayList <String> mUuidIntentTracker;
921caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static {
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        classInitNative();
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
97bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    public BluetoothService(Context context) {
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext = context;
99105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
100105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Need to do this in place of:
101105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // mBatteryStats = BatteryStatsService.getService();
102105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Since we can not import BatteryStatsService from here. This class really needs to be
103105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // moved to java/services/com/android/server/
104105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo"));
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        initializeNativeDataNative();
107ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project
108ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project        if (isEnabledNative() == 1) {
109ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project            Log.w(TAG, "Bluetooth daemons already running - runtime restart? ");
110ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project            disableNative();
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
112ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project
113de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        mBluetoothState = BluetoothAdapter.STATE_OFF;
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mIsDiscovering = false;
115bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mAdapterProperties = new HashMap<String, String>();
116bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mDeviceProperties = new HashMap<String, Map<String,String>>();
11710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
11810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        mDeviceServiceChannelCache = new HashMap<String, Map<ParcelUuid, Integer>>();
1191caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        mUuidIntentTracker = new ArrayList<String>();
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        registerForAirplaneMode();
121bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    }
122bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly
123bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    public synchronized void initAfterRegistration() {
124bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mAdapter = (BluetoothAdapter) mContext.getSystemService(Context.BLUETOOTH_SERVICE);
125bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mEventLoop = new BluetoothEventLoop(mContext, mAdapter, this);
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void finalize() throws Throwable {
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mIsAirplaneSensitive) {
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mContext.unregisterReceiver(mReceiver);
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            cleanupNativeDataNative();
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super.finalize();
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean isEnabled() {
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
142de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        return mBluetoothState == BluetoothAdapter.STATE_ON;
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
145105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    public int getBluetoothState() {
146105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
147105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        return mBluetoothState;
148105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    }
149105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
150105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Bring down bluetooth and disable BT in settings. Returns true on success.
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean disable() {
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return disable(true);
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Bring down bluetooth. Returns true on success.
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param saveSetting If true, disable BT in settings
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean disable(boolean saveSetting) {
164d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
166105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        switch (mBluetoothState) {
167de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_OFF:
168105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return true;
169de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_ON:
170105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            break;
171105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        default:
172105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return false;
173105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mEnableThread != null && mEnableThread.isAlive()) {
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
177de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        setBluetoothState(BluetoothAdapter.STATE_TURNING_OFF);
178105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
179105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Allow 3 seconds for profiles to gracefully disconnect
180105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // TODO: Introduce a callback mechanism so that each profile can notify
181bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        // BluetoothService when it is done shutting down
182105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mHandler.sendMessageDelayed(
183105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                mHandler.obtainMessage(MESSAGE_FINISH_DISABLE, saveSetting ? 1 : 0, 0), 3000);
184105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        return true;
185105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    }
186105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
187105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
188105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private synchronized void finishDisable(boolean saveSetting) {
189de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        if (mBluetoothState != BluetoothAdapter.STATE_TURNING_OFF) {
190105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return;
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mEventLoop.stop();
193d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        tearDownNativeDataNative();
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        disableNative();
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // mark in progress bondings as cancelled
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (String address : mBondState.listInState(BluetoothDevice.BOND_BONDING)) {
198005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            mBondState.setBondState(address, BluetoothDevice.BOND_NONE,
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // update mode
203de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        Intent intent = new Intent(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
204de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        intent.putExtra(BluetoothAdapter.EXTRA_SCAN_MODE, BluetoothAdapter.SCAN_MODE_NONE);
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.sendBroadcast(intent, BLUETOOTH_PERM);
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
207105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mIsDiscovering = false;
208bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mAdapterProperties.clear();
209105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (saveSetting) {
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            persistBluetoothOnSetting(false);
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
213105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
214de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        setBluetoothState(BluetoothAdapter.STATE_OFF);
215105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
216105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Log bluetooth off to battery stats.
217105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        long ident = Binder.clearCallingIdentity();
218105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        try {
219105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            mBatteryStats.noteBluetoothOff();
220105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        } catch (RemoteException e) {
221105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        } finally {
222105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            Binder.restoreCallingIdentity(ident);
223105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
224997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly
225997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        if (mRestart) {
226997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly            mRestart = false;
227997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly            enable();
228997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        }
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
231105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    /** Bring up BT and persist BT on in settings */
232105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    public boolean enable() {
233105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        return enable(true);
2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Enable this Bluetooth device, asynchronously.
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * This turns on/off the underlying hardware.
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
240105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project     * @param saveSetting If true, persist the new state of BT in settings
241105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project     * @return True on success (so far)
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
243105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    public synchronized boolean enable(boolean saveSetting) {
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Airplane mode can prevent Bluetooth radio from being turned on.
2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mIsAirplaneSensitive && isAirplaneModeOn()) {
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
251de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        if (mBluetoothState != BluetoothAdapter.STATE_OFF) {
2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mEnableThread != null && mEnableThread.isAlive()) {
2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
257de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        setBluetoothState(BluetoothAdapter.STATE_TURNING_ON);
258105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mEnableThread = new EnableThread(saveSetting);
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mEnableThread.start();
2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
263997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly    /** Forcibly restart Bluetooth if it is on */
264997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly    /* package */ synchronized void restart() {
265de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        if (mBluetoothState != BluetoothAdapter.STATE_ON) {
266997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly            return;
267997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        }
268997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        mRestart = true;
269997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        if (!disable(false)) {
270997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly            mRestart = false;
271997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        }
272d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
273997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly
274105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private synchronized void setBluetoothState(int state) {
275105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        if (state == mBluetoothState) {
276105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return;
277105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
278105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
279105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        if (DBG) log("Bluetooth state " + mBluetoothState + " -> " + state);
280105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
281de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
282de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, mBluetoothState);
283de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        intent.putExtra(BluetoothAdapter.EXTRA_STATE, state);
284105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
285105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
286105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mBluetoothState = state;
287105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
288105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mContext.sendBroadcast(intent, BLUETOOTH_PERM);
289105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    }
290105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final Handler mHandler = new Handler() {
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void handleMessage(Message msg) {
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            switch (msg.what) {
295105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            case MESSAGE_REGISTER_SDP_RECORDS:
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                //TODO: Don't assume HSP/HFP is running, don't use sdptool,
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (isEnabled()) {
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    SystemService.start("hsag");
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    SystemService.start("hfag");
30003c707ab6fc97e99b1603b8d6edc604dbea3cd6fNick Pelly                    SystemService.start("opush");
30167542964876aa7e4216e8f69f21dda68e7463b9aJaikumar Ganesh                    SystemService.start("pbap");
3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
303105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                break;
304105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            case MESSAGE_FINISH_DISABLE:
305105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                finishDisable(msg.arg1 != 0);
306105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                break;
3071caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            case MESSAGE_UUID_INTENT:
3081caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh                String address = (String)msg.obj;
3091caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh                if (address != null)
3101caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh                    sendUuidIntent(address);
3111caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh                break;
31212835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            case MESSAGE_DISCOVERABLE_TIMEOUT:
31312835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                int mode = msg.arg1;
31412835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                if (isEnabled()) {
31512835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                    // TODO: Switch back to the previous scan mode
31612835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                    // This is ok for now, because we only use
31712835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                    // CONNECTABLE and CONNECTABLE_DISCOVERABLE
31812835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                    setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE, -1);
31912835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                }
32012835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                break;
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private EnableThread mEnableThread;
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private class EnableThread extends Thread {
3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final boolean mSaveSetting;
329105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        public EnableThread(boolean saveSetting) {
3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mSaveSetting = saveSetting;
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void run() {
3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean res = (enableNative() == 0);
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (res) {
335b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                int retryCount = 2;
336b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                boolean running = false;
337b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                while ((retryCount-- > 0) && !running) {
338b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    mEventLoop.start();
339105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    // it may take a momement for the other thread to do its
340b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    // thing.  Check periodically for a while.
341b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    int pollCount = 5;
342b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    while ((pollCount-- > 0) && !running) {
343b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                        if (mEventLoop.isEventLoopRunning()) {
344b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                            running = true;
345b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                            break;
346b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                        }
347b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                        try {
348b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                            Thread.sleep(100);
349b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                        } catch (InterruptedException e) {}
350b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    }
351b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                }
352b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                if (!running) {
353b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    log("bt EnableThread giving up");
354b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    res = false;
355b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    disableNative();
356b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                }
3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (res) {
361d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                if (!setupNativeDataNative()) {
362d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                    return;
363d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                }
3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mSaveSetting) {
3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    persistBluetoothOnSetting(true);
3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mIsDiscovering = false;
3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mBondState.loadBondState();
369105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                mHandler.sendMessageDelayed(mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS),
370105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                                            3000);
3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
372105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                // Log bluetooth on to battery stats.
373105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                long ident = Binder.clearCallingIdentity();
374105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                try {
375105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    mBatteryStats.noteBluetoothOn();
376105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                } catch (RemoteException e) {
377105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                } finally {
378105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    Binder.restoreCallingIdentity(ident);
379105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                }
3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
381105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
382105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            mEnableThread = null;
383105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
384105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            setBluetoothState(res ?
385de893f550301a60274e87aa8168225e7a7a42184Nick Pelly                              BluetoothAdapter.STATE_ON :
386de893f550301a60274e87aa8168225e7a7a42184Nick Pelly                              BluetoothAdapter.STATE_OFF);
387105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
388b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            if (res) {
389105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                // Update mode
390d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                String[] propVal = {"Pairable", getProperty("Pairable")};
391d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                mEventLoop.onPropertyChanged(propVal);
392b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            }
393b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project
3945c43f735d94a538dc273c8f859d1100a7cdd5c71Daisuke Miyakawa            if (mIsAirplaneSensitive && isAirplaneModeOn()) {
3955c43f735d94a538dc273c8f859d1100a7cdd5c71Daisuke Miyakawa                disable(false);
3965c43f735d94a538dc273c8f859d1100a7cdd5c71Daisuke Miyakawa            }
3975c43f735d94a538dc273c8f859d1100a7cdd5c71Daisuke Miyakawa
3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void persistBluetoothOnSetting(boolean bluetoothOn) {
4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long origCallerIdentityToken = Binder.clearCallingIdentity();
4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.BLUETOOTH_ON,
4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                bluetoothOn ? 1 : 0);
4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Binder.restoreCallingIdentity(origCallerIdentityToken);
4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* package */ BondState getBondState() {
4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mBondState;
4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** local cache of bonding state.
4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* we keep our own state to track the intermediate state BONDING, which
4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* bluez does not track.
4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * All addreses must be passed in upper case.
4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public class BondState {
4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final HashMap<String, Integer> mState = new HashMap<String, Integer>();
4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final HashMap<String, Integer> mPinAttempt = new HashMap<String, Integer>();
4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final ArrayList<String> mAutoPairingFailures = new ArrayList<String>();
421105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // List of all the vendor_id prefix of Bluetooth addresses for
422105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // which auto pairing is not attempted.
423105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // The following companies are included in the list below:
424105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // ALPS (lexus), Murata (Prius 2007, Nokia 616), TEMIC SDS (Porsche, Audi),
425105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Parrot, Zhongshan General K-mate Electronics, Great Well
426105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Electronics, Flaircomm Electronics, Jatty Electronics, Delphi,
427105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Clarion, Novero, Denso (Lexus, Toyota), Johnson Controls (Acura),
428adbaef234e1bd7bbec561fb6291bae394a412ce8Nick Pelly        // Continental Automotive, Harman/Becker, Panasonic/Kyushu Ten
429482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh        private final ArrayList<String>  mAutoPairingAddressBlacklist =
4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                new ArrayList<String>(Arrays.asList(
431105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                        "00:02:C7", "00:16:FE", "00:19:C1", "00:1B:FB", "00:1E:3D", "00:21:4F",
432105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                        "00:23:06", "00:24:33", "00:A0:79", "00:0E:6D", "00:13:E0", "00:21:E8",
433105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                        "00:60:57", "00:0E:9F", "00:12:1C", "00:18:91", "00:18:96", "00:13:04",
434105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                        "00:16:FD", "00:22:A0", "00:0B:4C", "00:60:6F", "00:23:3D", "00:C0:59",
435adbaef234e1bd7bbec561fb6291bae394a412ce8Nick Pelly                        "00:0A:30", "00:1E:AE", "00:1C:D7", "00:80:F0"
4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        ));
4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
438482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh        // List of names of Bluetooth devices for which auto pairing should be
439482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh        // disabled.
440482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh        private final ArrayList<String> mAutoPairingNameBlacklist =
441482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh                new ArrayList<String>(Arrays.asList(
442482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh                        "Motorola IHF1000", "i.TechBlueBAND", "X5 Stereo v1.3"));
443482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh
4442092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        // If this is an outgoing connection, store the address.
4452092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        // There can be only 1 pending outgoing connection at a time,
4462092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        private String mPendingOutgoingBonding;
4472092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
4482092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        private synchronized void setPendingOutgoingBonding(String address) {
4492092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh            mPendingOutgoingBonding = address;
4502092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        }
4512092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
4522092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        public synchronized String getPendingOutgoingBonding() {
4532092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh            return mPendingOutgoingBonding;
4542092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        }
4552092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized void loadBondState() {
457de893f550301a60274e87aa8168225e7a7a42184Nick Pelly            if (mBluetoothState != BluetoothAdapter.STATE_TURNING_ON) {
4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
460d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            String []bonds = null;
461d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            String val = getProperty("Devices");
462d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            if (val != null) {
463d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                bonds = val.split(",");
464d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            }
4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (bonds == null) {
4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mState.clear();
4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (DBG) log("found " + bonds.length + " bonded devices");
470d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            for (String device : bonds) {
471d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                mState.put(getAddressFromObjectPath(device).toUpperCase(),
472d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                        BluetoothDevice.BOND_BONDED);
4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized void setBondState(String address, int state) {
4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setBondState(address, state, 0);
4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /** reason is ignored unless state == BOND_NOT_BONDED */
4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized void setBondState(String address, int state, int reason) {
4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int oldState = getBondState(address);
4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (oldState == state) {
4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4862092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
4872092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh            // Check if this was an pending outgoing bonding.
4882092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh            // If yes, reset the state.
4892092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh            if (oldState == BluetoothDevice.BOND_BONDING) {
4902092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh                if (address.equals(mPendingOutgoingBonding)) {
4912092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh                    mPendingOutgoingBonding = null;
4922092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh                }
4932092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh            }
4942092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (DBG) log(address + " bond state " + oldState + " -> " + state + " (" +
4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                         reason + ")");
497005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            Intent intent = new Intent(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
498005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
499005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            intent.putExtra(BluetoothDevice.EXTRA_BOND_STATE, state);
500005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            intent.putExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, oldState);
501005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            if (state == BluetoothDevice.BOND_NONE) {
5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (reason <= 0) {
5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Log.w(TAG, "setBondState() called to unbond device, but reason code is " +
5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                          "invalid. Overriding reason code with BOND_RESULT_REMOVED");
5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    reason = BluetoothDevice.UNBOND_REASON_REMOVED;
5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
507005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly                intent.putExtra(BluetoothDevice.EXTRA_REASON, reason);
5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mState.remove(address);
5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mState.put(address, state);
5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mContext.sendBroadcast(intent, BLUETOOTH_PERM);
5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public boolean isAutoPairingBlacklisted(String address) {
517482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh            for (String blacklistAddress : mAutoPairingAddressBlacklist) {
5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (address.startsWith(blacklistAddress)) return true;
5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
520482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh
521482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh            String name = getRemoteName(address);
522482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh            if (name != null) {
523482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh                for (String blacklistName : mAutoPairingNameBlacklist) {
524482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh                    if (name.equals(blacklistName)) return true;
525482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh                }
526482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh            }
5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized int getBondState(String address) {
5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Integer state = mState.get(address);
5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (state == null) {
533005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly                return BluetoothDevice.BOND_NONE;
5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return state.intValue();
5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private synchronized String[] listInState(int state) {
5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ArrayList<String> result = new ArrayList<String>(mState.size());
5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (Map.Entry<String, Integer> e : mState.entrySet()) {
5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (e.getValue().intValue() == state) {
5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    result.add(e.getKey());
5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return result.toArray(new String[result.size()]);
5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized void addAutoPairingFailure(String address) {
5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (!mAutoPairingFailures.contains(address)) {
5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mAutoPairingFailures.add(address);
5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized boolean isAutoPairingAttemptsInProgress(String address) {
5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return getAttempt(address) != 0;
5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized void clearPinAttempts(String address) {
5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mPinAttempt.remove(address);
5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized boolean hasAutoPairingFailed(String address) {
5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mAutoPairingFailures.contains(address);
5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized int getAttempt(String address) {
5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Integer attempt = mPinAttempt.get(address);
5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (attempt == null) {
5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return 0;
5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return attempt.intValue();
5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized void attempt(String address) {
5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Integer attempt = mPinAttempt.get(address);
5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int newAttempt;
5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (attempt == null) {
5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                newAttempt = 1;
5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                newAttempt = attempt.intValue() + 1;
5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mPinAttempt.put(address, new Integer(newAttempt));
5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static String toBondStateString(int bondState) {
5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        switch (bondState) {
589005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        case BluetoothDevice.BOND_NONE:
5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "not bonded";
5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case BluetoothDevice.BOND_BONDING:
5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "bonding";
5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case BluetoothDevice.BOND_BONDED:
5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "bonded";
5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        default:
5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "??????";
5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6009519ce75f15ba287a641166c1b7ed10f2aa73f74Jaikumar Ganesh    /*package*/ synchronized boolean isAdapterPropertiesEmpty() {
6019519ce75f15ba287a641166c1b7ed10f2aa73f74Jaikumar Ganesh        return mAdapterProperties.isEmpty();
6029519ce75f15ba287a641166c1b7ed10f2aa73f74Jaikumar Ganesh    }
6039519ce75f15ba287a641166c1b7ed10f2aa73f74Jaikumar Ganesh
604d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /*package*/synchronized void getAllProperties() {
6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
606bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mAdapterProperties.clear();
607d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
608d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String properties[] = (String [])getAdapterPropertiesNative();
609d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        // The String Array consists of key-value pairs.
610d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (properties == null) {
611d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            Log.e(TAG, "*Error*: GetAdapterProperties returned NULL");
612d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return;
613d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
614d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
6158bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh        for (int i = 0; i < properties.length; i++) {
6168bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            String name = properties[i];
617efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh            String newValue = null;
6188bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            int len;
6198bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            if (name == null) {
6208bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                Log.e(TAG, "Error:Adapter Property at index" + i + "is null");
6218bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                continue;
6228bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            }
6238bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            if (name.equals("Devices")) {
624efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                StringBuilder str = new StringBuilder();
6258bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                len = Integer.valueOf(properties[++i]);
6268bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                for (int j = 0; j < len; j++) {
627efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                    str.append(properties[++i]);
628efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                    str.append(",");
629efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                }
630efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                if (len > 0) {
631efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                    newValue = str.toString();
6328bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                }
6338bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            } else {
6348bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                newValue = properties[++i];
6358bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            }
636bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            mAdapterProperties.put(name, newValue);
637d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
638d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
639d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        // Add adapter object path property.
640d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String adapterPath = getAdapterPathNative();
641d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (adapterPath != null)
642bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            mAdapterProperties.put("ObjectPath", adapterPath + "/dev_");
6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
645d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ synchronized void setProperty(String name, String value) {
646bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mAdapterProperties.put(name, value);
6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean setName(String name) {
6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (name == null) {
6539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
6549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
655d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setPropertyString("Name", name);
6569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
658d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    //TODO(): setPropertyString, setPropertyInteger, setPropertyBoolean
659d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    // Either have a single property function with Object as the parameter
660d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    // or have a function for each property and then obfuscate in the JNI layer.
661d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    // The following looks dirty.
662d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private boolean setPropertyString(String key, String value) {
6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
664d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setAdapterPropertyStringNative(key, value);
6659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
667d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private boolean setPropertyInteger(String key, int value) {
668d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
669d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setAdapterPropertyIntegerNative(key, value);
670d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
672d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private boolean setPropertyBoolean(String key, boolean value) {
673d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
674d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setAdapterPropertyBooleanNative(key, value ? 1 : 0);
6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
677d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /**
678d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Set the discoverability window for the device.  A timeout of zero
679d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * makes the device permanently discoverable (if the device is
680d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * discoverable).  Setting the timeout to a nonzero value does not make
681d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * a device discoverable; you need to call setMode() to make the device
682d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * explicitly discoverable.
683d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     *
684d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * @param timeout_s The discoverable timeout in seconds.
685d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     */
686d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized boolean setDiscoverableTimeout(int timeout) {
6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
689d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setPropertyInteger("DiscoverableTimeout", timeout);
6909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
69212835478ee687a493d1b5882e67b6725bd539c26Nick Pelly    public synchronized boolean setScanMode(int mode, int duration) {
69318b1e79a123b979d25bfa5d0b0ee5d0382dbd64bNick Pelly        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS,
69418b1e79a123b979d25bfa5d0b0ee5d0382dbd64bNick Pelly                                                "Need WRITE_SECURE_SETTINGS permission");
695de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        boolean pairable = false;
696de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        boolean discoverable = false;
69712835478ee687a493d1b5882e67b6725bd539c26Nick Pelly
698de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        switch (mode) {
699de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.SCAN_MODE_NONE:
70012835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            mHandler.removeMessages(MESSAGE_DISCOVERABLE_TIMEOUT);
701d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            pairable = false;
702d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            discoverable = false;
703de893f550301a60274e87aa8168225e7a7a42184Nick Pelly            break;
704de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
70512835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            mHandler.removeMessages(MESSAGE_DISCOVERABLE_TIMEOUT);
706d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            pairable = true;
707d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            discoverable = false;
708005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            break;
709de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
71012835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            mHandler.removeMessages(MESSAGE_DISCOVERABLE_TIMEOUT);
711d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            pairable = true;
712d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            discoverable = true;
71312835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            Message msg = mHandler.obtainMessage(MESSAGE_DISCOVERABLE_TIMEOUT);
71412835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            mHandler.sendMessageDelayed(msg, duration * 1000);
71512835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            if (DBG) Log.d(TAG, "BT Discoverable for " + duration + " seconds");
716005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            break;
717de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        default:
718de893f550301a60274e87aa8168225e7a7a42184Nick Pelly            Log.w(TAG, "Requested invalid scan mode " + mode);
719de893f550301a60274e87aa8168225e7a7a42184Nick Pelly            return false;
720d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
721d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        setPropertyBoolean("Pairable", pairable);
722d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        setPropertyBoolean("Discoverable", discoverable);
7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
724d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return true;
7259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
727d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /*package*/ synchronized String getProperty (String name) {
728bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        if (!mAdapterProperties.isEmpty())
729bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            return mAdapterProperties.get(name);
730d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        getAllProperties();
731bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        return mAdapterProperties.get(name);
7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
734d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized String getAddress() {
735d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
736d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return getProperty("Address");
7379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
739d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized String getName() {
7409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
741d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return getProperty("Name");
7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
745d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Returns the user-friendly name of a remote device.  This value is
746d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * returned from our local cache, which is updated when onPropertyChange
747d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * event is received.
748d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Do not expect to retrieve the updated remote name immediately after
749d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * changing the name on the remote device.
7509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
751d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * @param address Bluetooth address of remote device.
752d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     *
753d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * @return The user-friendly name of the specified remote device.
7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
755d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized String getRemoteName(String address) {
756d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
757005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
758d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return null;
759d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
760bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        Map <String, String> properties = mDeviceProperties.get(address);
761d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (properties != null) return properties.get("Name");
762d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return null;
7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
7669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Get the discoverability window for the device.  A timeout of zero
7679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * means that the device is permanently discoverable (if the device is
7689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * in the discoverable mode).
7699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
7709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The discoverability window of the device, in seconds.  A negative
7719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         value indicates an error.
7729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
7739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized int getDiscoverableTimeout() {
7749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
775d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String timeout = getProperty("DiscoverableTimeout");
776d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (timeout != null)
777d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh           return Integer.valueOf(timeout);
778d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        else
779d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return -1;
7809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized int getScanMode() {
7839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
784d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (!isEnabled())
785de893f550301a60274e87aa8168225e7a7a42184Nick Pelly            return BluetoothAdapter.SCAN_MODE_NONE;
786d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
787d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        boolean pairable = getProperty("Pairable").equals("true");
788d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        boolean discoverable = getProperty("Discoverable").equals("true");
789d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return bluezStringToScanMode (pairable, discoverable);
7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
792d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized boolean startDiscovery() {
7939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
7949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
795d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (!isEnabled()) {
796d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return false;
7979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
798d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return startDiscoveryNative();
7999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
801d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized boolean cancelDiscovery() {
8029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
8039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
804d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return stopDiscoveryNative();
805d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
806d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
807d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized boolean isDiscovering() {
808d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
809d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return mIsDiscovering;
810d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
811d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
812d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ void setIsDiscovering(boolean isDiscovering) {
813d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mIsDiscovering = isDiscovering;
8149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean createBond(String address) {
8179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
8189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
819005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
8209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
8219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        address = address.toUpperCase();
8239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8242092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        if (mBondState.getPendingOutgoingBonding() != null) {
8259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            log("Ignoring createBond(): another device is bonding");
8269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // a different device is currently bonding, fail
8279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
8289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Check for bond state only if we are not performing auto
8319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // pairing exponential back-off attempts.
8329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mBondState.isAutoPairingAttemptsInProgress(address) &&
833005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly                mBondState.getBondState(address) != BluetoothDevice.BOND_NONE) {
8349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            log("Ignoring createBond(): this device is already bonding or bonded");
8359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
8369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
838d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (!createPairedDeviceNative(address, 60000 /* 1 minute */)) {
8399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
8409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8422092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        mBondState.setPendingOutgoingBonding(address);
8439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mBondState.setBondState(address, BluetoothDevice.BOND_BONDING);
8442092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
8469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean cancelBondProcess(String address) {
8499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
8509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
851005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
8529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
8539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        address = address.toUpperCase();
8559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mBondState.getBondState(address) != BluetoothDevice.BOND_BONDING) {
8569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
859005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        mBondState.setBondState(address, BluetoothDevice.BOND_NONE,
8609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
861d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        cancelDeviceCreationNative(address);
8629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
8639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean removeBond(String address) {
8669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
8679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
868005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
8699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
8709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
871d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return removeDeviceNative(getObjectPathFromAddress(address));
8729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized String[] listBonds() {
8759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
8769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mBondState.listInState(BluetoothDevice.BOND_BONDED);
8779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized int getBondState(String address) {
8809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
881005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
882b24e11baac589fe16426f2d243b460ab84991c7bNick Pelly            return BluetoothDevice.ERROR;
8839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mBondState.getBondState(address.toUpperCase());
8859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8879488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh    /*package*/ boolean isRemoteDeviceInCache(String address) {
888bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        return (mDeviceProperties.get(address) != null);
8899488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh    }
8909488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh
8919488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh    /*package*/ String[] getRemoteDeviceProperties(String address) {
8929488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh        String objectPath = getObjectPathFromAddress(address);
8939488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh        return (String [])getDevicePropertiesNative(objectPath);
8949488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh    }
8959488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh
896d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /*package*/ synchronized String getRemoteDeviceProperty(String address, String property) {
897bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        Map<String, String> properties = mDeviceProperties.get(address);
898d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (properties != null) {
899d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return properties.get(property);
900d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        } else {
901d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            // Query for remote device properties, again.
902d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            // We will need to reload the cache when we switch Bluetooth on / off
903d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            // or if we crash.
90410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            if (updateRemoteDevicePropertiesCache(address))
905d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                return getRemoteDeviceProperty(address, property);
9069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
907d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        Log.e(TAG, "getRemoteDeviceProperty: " + property + "not present:" + address);
908d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return null;
9099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
91110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh    /* package */ synchronized boolean updateRemoteDevicePropertiesCache(String address) {
91210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        String[] propValues = getRemoteDeviceProperties(address);
91310eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        if (propValues != null) {
91410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            addRemoteDeviceProperties(address, propValues);
91510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            return true;
91610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        }
91710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        return false;
91810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh    }
91910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
920d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ synchronized void addRemoteDeviceProperties(String address, String[] properties) {
921395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh        /*
922395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh         * We get a DeviceFound signal every time RSSI changes or name changes.
923395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh         * Don't create a new Map object every time */
924bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        Map<String, String> propertyValues = mDeviceProperties.get(address);
925efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh        if (propertyValues == null) {
926395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh            propertyValues = new HashMap<String, String>();
927395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh        }
928395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh
9298bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh        for (int i = 0; i < properties.length; i++) {
9308bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            String name = properties[i];
931efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh            String newValue = null;
9328bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            int len;
9338bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            if (name == null) {
9348bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                Log.e(TAG, "Error: Remote Device Property at index" + i + "is null");
9358bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                continue;
9368bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            }
9378bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            if (name.equals("UUIDs") || name.equals("Nodes")) {
938efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                StringBuilder str = new StringBuilder();
9398bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                len = Integer.valueOf(properties[++i]);
9408bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                for (int j = 0; j < len; j++) {
941efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                    str.append(properties[++i]);
942efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                    str.append(",");
943efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                }
944efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                if (len > 0) {
945efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                    newValue = str.toString();
9468bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                }
947d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            } else {
9488bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                newValue = properties[++i];
949d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            }
950efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh
9518bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            propertyValues.put(name, newValue);
9529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
953bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mDeviceProperties.put(address, propertyValues);
95410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
95510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        // We have added a new remote device or updated its properties.
95610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        // Also update the serviceChannel cache.
95710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        updateDeviceServiceChannelCache(address);
9589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
960d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ void removeRemoteDeviceProperties(String address) {
961bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mDeviceProperties.remove(address);
9629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
964d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ synchronized void setRemoteDeviceProperty(String address, String name,
965d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                                                              String value) {
966bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        Map <String, String> propVal = mDeviceProperties.get(address);
967d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (propVal != null) {
968d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            propVal.put(name, value);
969bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            mDeviceProperties.put(address, propVal);
970d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        } else {
971d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            Log.e(TAG, "setRemoteDeviceProperty for a device not in cache:" + address);
9729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
976efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * Sets the remote device trust state.
977efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     *
978efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * @return boolean to indicate operation success or fail
979efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     */
980efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    public synchronized boolean setTrust(String address, boolean value) {
981005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
982efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
983efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            return false;
984efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        }
985efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue
986efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        return setDevicePropertyBooleanNative(getObjectPathFromAddress(address), "Trusted",
987efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue                value ? 1 : 0);
988efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    }
989efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue
990efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    /**
991efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * Gets the remote device trust state as boolean.
992efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * Note: this value may be
993efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * retrieved from cache if we retrieved the data before *
994efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     *
995efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * @return boolean to indicate trust or untrust state
996efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     */
997efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    public synchronized boolean getTrustState(String address) {
998005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
999efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1000efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            return false;
1001efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        }
1002efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue
1003efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        String val = getRemoteDeviceProperty(address, "Trusted");
1004efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        if (val == null) {
1005efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            return false;
1006efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        } else {
1007efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            return val.equals("true") ? true : false;
1008efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        }
1009efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    }
1010efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue
1011efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    /**
1012d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Gets the remote major, minor classes encoded as a 32-bit
10139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * integer.
10149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
10159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Note: this value is retrieved from cache, because we get it during
10169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *       remote-device discovery.
10179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
10189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return 32-bit integer encoding the remote major, minor, and service
10199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         classes.
10209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
10219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized int getRemoteClass(String address) {
1022005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1023ea600ccfb7568f60377c4abc85f56c80af7fdbfcNick Pelly            mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1024ea600ccfb7568f60377c4abc85f56c80af7fdbfcNick Pelly            return BluetoothClass.ERROR;
10259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1026d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String val = getRemoteDeviceProperty(address, "Class");
1027d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (val == null)
1028d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return BluetoothClass.ERROR;
1029d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        else {
1030d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return Integer.valueOf(val);
1031d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
10329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1033d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
10349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1036dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh     * Gets the UUIDs supported by the remote device
10379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1038dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh     * @return array of 128bit ParcelUuids
10399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1040dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh    public synchronized ParcelUuid[] getRemoteUuids(String address) {
10419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1042005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
10439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return null;
10449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10451caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        return getUuidFromCache(address);
10461caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    }
10471caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
10481caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    private ParcelUuid[] getUuidFromCache(String address) {
1049d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String value = getRemoteDeviceProperty(address, "UUIDs");
1050dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        if (value == null) return null;
1051dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh
1052dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        String[] uuidStrings = null;
1053d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        // The UUIDs are stored as a "," separated string.
1054dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        uuidStrings = value.split(",");
1055dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        ParcelUuid[] uuids = new ParcelUuid[uuidStrings.length];
1056dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh
1057dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        for (int i = 0; i < uuidStrings.length; i++) {
1058dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh            uuids[i] = ParcelUuid.fromString(uuidStrings[i]);
1059dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        }
1060d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return uuids;
10619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10631caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    public synchronized boolean fetchRemoteUuidsWithSdp(String address) {
10641caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
10651caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
10661caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            return false;
10671caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        }
10681caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
10691caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        if (mUuidIntentTracker.contains(address)) {
10701caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            // An SDP query for this address is already in progress
10711caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            return true;
10721caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        }
10731caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
10741caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        boolean ret;
10751caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        if (getBondState(address) == BluetoothDevice.BOND_BONDED) {
10761caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            String path = getObjectPathFromAddress(address);
10771caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            if (path == null) return false;
10781caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
10791caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            // Use an empty string for the UUID pattern
10801caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            ret = discoverServicesNative(path, "");
10811caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        } else {
10821caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            ret = createDeviceNative(address);
10831caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        }
10841caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
10851caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        mUuidIntentTracker.add(address);
10861caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
10871caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        Message message = mHandler.obtainMessage(MESSAGE_UUID_INTENT);
10881caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        message.obj = address;
10891caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        mHandler.sendMessageDelayed(message, UUID_INTENT_DELAY);
10901caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        return ret;
10911caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    }
10921caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
10939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1094d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Gets the rfcomm channel associated with the UUID.
10959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1096d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * @param address Address of the remote device
1097dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh     * @param uuid ParcelUuid of the service attribute
10989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1099d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * @return rfcomm channel associated with the service attribute
110010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh     *         -1 on error
11019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1102dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh    public int getRemoteServiceChannel(String address, ParcelUuid uuid) {
11039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1104005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1105b24e11baac589fe16426f2d243b460ab84991c7bNick Pelly            return BluetoothDevice.ERROR;
11069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
110710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        // Check if we are recovering from a crash.
110810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        if (mDeviceProperties.isEmpty()) {
110910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            if (!updateRemoteDevicePropertiesCache(address))
111010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh                return -1;
111110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        }
111210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
111310eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        Map<ParcelUuid, Integer> value = mDeviceServiceChannelCache.get(address);
111410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        if (value != null && value.containsKey(uuid))
111510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            return value.get(uuid);
111610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        return -1;
11179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean setPin(String address, byte[] pin) {
11209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
11219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
11229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (pin == null || pin.length <= 0 || pin.length > 16 ||
1123005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            !BluetoothAdapter.checkBluetoothAddress(address)) {
11249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
11259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        address = address.toUpperCase();
11279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
11289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (data == null) {
11299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.w(TAG, "setPin(" + address + ") called but no native data available, " +
11309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                  "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
11319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                  " or by bluez.\n");
11329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
11339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // bluez API wants pin as a string
11359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String pinString;
11369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
11379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pinString = new String(pin, "UTF8");
11389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (UnsupportedEncodingException uee) {
11399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.e(TAG, "UTF8 not supported?!?");
11409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
11419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return setPinNative(address, pinString, data.intValue());
11439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1145b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    public synchronized boolean setPasskey(String address, int passkey) {
1146b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1147b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                                                "Need BLUETOOTH_ADMIN permission");
1148005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (passkey < 0 || passkey > 999999 || !BluetoothAdapter.checkBluetoothAddress(address)) {
1149b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            return false;
1150b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        }
1151b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        address = address.toUpperCase();
1152b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
1153b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        if (data == null) {
1154b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            Log.w(TAG, "setPasskey(" + address + ") called but no native data available, " +
1155b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                  "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
1156b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                  " or by bluez.\n");
1157b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            return false;
1158b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        }
1159b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        return setPasskeyNative(address, passkey, data.intValue());
1160b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    }
1161b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh
1162b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    public synchronized boolean setPairingConfirmation(String address, boolean confirm) {
1163b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1164b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                                                "Need BLUETOOTH_ADMIN permission");
1165b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        address = address.toUpperCase();
1166b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
1167b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        if (data == null) {
1168b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            Log.w(TAG, "setPasskey(" + address + ") called but no native data available, " +
1169b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                  "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
1170b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                  " or by bluez.\n");
1171b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            return false;
1172b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        }
1173b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        return setPairingConfirmationNative(address, confirm, data.intValue());
1174b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    }
1175b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh
1176b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    public synchronized boolean cancelPairingUserInput(String address) {
11779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
11789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
1179005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
11809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
11819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1182005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        mBondState.setBondState(address, BluetoothDevice.BOND_NONE,
1183397d8f4f4829a45f4fe7a672cc395466bbc0f442Jaikumar Ganesh                BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
11849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        address = address.toUpperCase();
11859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
11869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (data == null) {
1187b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            Log.w(TAG, "cancelUserInputNative(" + address + ") called but no native data " +
1188b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                "available, ignoring. Maybe the PasskeyAgent Request was already cancelled " +
1189b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                "by the remote or by bluez.\n");
11909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
11919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1192b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        return cancelPairingUserInputNative(address, data.intValue());
11939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
119510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh    public void updateDeviceServiceChannelCache(String address) {
119610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        ParcelUuid[] deviceUuids = getRemoteUuids(address);
119710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        // We are storing the rfcomm channel numbers only for the uuids
119810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        // we are interested in.
119910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        int channel;
120010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        ParcelUuid[] interestedUuids = {BluetoothUuid.Handsfree,
120110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh                                        BluetoothUuid.HSP,
120210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh                                        BluetoothUuid.ObexObjectPush};
120310eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
120410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        Map <ParcelUuid, Integer> value = new HashMap<ParcelUuid, Integer>();
120510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        for (ParcelUuid uuid: interestedUuids) {
120610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            if (BluetoothUuid.isUuidPresent(deviceUuids, uuid)) {
120710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh                channel =
120810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh                   getDeviceServiceChannelNative(getObjectPathFromAddress(address), uuid.toString(),
120910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh                                                 0x0004);
121010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh                value.put(uuid, channel);
121110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            }
121210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        }
121310eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        mDeviceServiceChannelCache.put(address, value);
121410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh    }
121510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
12169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
12179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
12189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onReceive(Context context, Intent intent) {
12199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String action = intent.getAction();
12209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
12219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ContentResolver resolver = context.getContentResolver();
12229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Query the airplane mode from Settings.System just to make sure that
12239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // some random app is not sending this intent and disabling bluetooth
12249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                boolean enabled = !isAirplaneModeOn();
12259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // If bluetooth is currently expected to be on, then enable or disable bluetooth
12269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (Settings.Secure.getInt(resolver, Settings.Secure.BLUETOOTH_ON, 0) > 0) {
12279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (enabled) {
1228105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                        enable(false);
12299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } else {
12309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        disable(false);
12319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
12329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
12339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
12349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
12369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void registerForAirplaneMode() {
12389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String airplaneModeRadios = Settings.System.getString(mContext.getContentResolver(),
12399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Settings.System.AIRPLANE_MODE_RADIOS);
12409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mIsAirplaneSensitive = airplaneModeRadios == null
12419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ? true : airplaneModeRadios.contains(Settings.System.RADIO_BLUETOOTH);
12429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mIsAirplaneSensitive) {
12439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mIntentFilter = new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
12449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mContext.registerReceiver(mReceiver, mIntentFilter);
12459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* Returns true if airplane mode is currently on */
12499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final boolean isAirplaneModeOn() {
12509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return Settings.System.getInt(mContext.getContentResolver(),
12519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Settings.System.AIRPLANE_MODE_ON, 0) == 1;
12529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12541caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    /* Broadcast the Uuid intent */
12551caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    /*package*/ synchronized void sendUuidIntent(String address) {
12566179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh        ParcelUuid[] uuid = getUuidFromCache(address);
12576179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh        Intent intent = new Intent(BluetoothDevice.ACTION_UUID);
12582d3b98d868cda30535505b2a2fba47aa1c9c052bJaikumar Ganesh        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
12596179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh        intent.putExtra(BluetoothDevice.EXTRA_UUID, uuid);
12606179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh        mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
12611caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
12626179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh        if (mUuidIntentTracker.contains(address))
12631caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            mUuidIntentTracker.remove(address);
12641caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    }
12651caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
12669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
12679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1268105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        pw.println("\nmIsAirplaneSensitive = " + mIsAirplaneSensitive + "\n");
1269105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
1270105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        switch(mBluetoothState) {
1271de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_OFF:
1272105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            pw.println("\nBluetooth OFF\n");
1273105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return;
1274de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_TURNING_ON:
1275105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            pw.println("\nBluetooth TURNING ON\n");
1276105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return;
1277de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_TURNING_OFF:
1278105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            pw.println("\nBluetooth TURNING OFF\n");
1279105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return;
1280de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_ON:
1281105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            pw.println("\nBluetooth ON\n");
1282105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
1283105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
1284105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        pw.println("\nLocal address = " + getAddress());
1285105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        pw.println("\nLocal name = " + getName());
1286105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        pw.println("\nisDiscovering() = " + isDiscovering());
1287105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
1288105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        BluetoothHeadset headset = new BluetoothHeadset(mContext, null);
1289105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
1290105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        pw.println("\n--Known devices--");
1291bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        for (String address : mDeviceProperties.keySet()) {
12921eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly            int bondState = mBondState.getBondState(address);
1293105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            pw.printf("%s %10s (%d) %s\n", address,
12941eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly                       toBondStateString(bondState),
1295105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                       mBondState.getAttempt(address),
1296105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                       getRemoteName(address));
12971eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly            if (bondState == BluetoothDevice.BOND_BONDED) {
1298dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh                ParcelUuid[] uuids = getRemoteUuids(address);
12991eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly                if (uuids == null) {
13001eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly                    pw.printf("\tuuids = null\n");
13011eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly                } else {
1302dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh                    for (ParcelUuid uuid : uuids) {
1303b015e193b7304230749bbf1e0676628b8a38de77Nick Pelly                        pw.printf("\t" + uuid + "\n");
13041eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly                    }
13051eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly                }
13061eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly            }
1307105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
1308105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
1309d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String value = getProperty("Devices");
13101eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly        String[] devicesObjectPath = null;
1311d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (value != null) {
1312d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            devicesObjectPath = value.split(",");
1313d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
1314105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        pw.println("\n--ACL connected devices--");
1315d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        for (String device : devicesObjectPath) {
1316d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            pw.println(getAddressFromObjectPath(device));
1317105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
1318105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
1319105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Rather not do this from here, but no-where else and I need this
1320105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // dump
1321105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        pw.println("\n--Headset Service--");
1322105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        switch (headset.getState()) {
1323105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        case BluetoothHeadset.STATE_DISCONNECTED:
1324105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            pw.println("getState() = STATE_DISCONNECTED");
1325105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            break;
1326105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        case BluetoothHeadset.STATE_CONNECTING:
1327105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            pw.println("getState() = STATE_CONNECTING");
1328105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            break;
1329105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        case BluetoothHeadset.STATE_CONNECTED:
1330105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            pw.println("getState() = STATE_CONNECTED");
1331105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            break;
1332105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        case BluetoothHeadset.STATE_ERROR:
1333105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            pw.println("getState() = STATE_ERROR");
1334105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            break;
1335105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
1336bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        pw.println("getCurrentHeadset() = " + headset.getCurrentHeadset());
13376c901db72dbaf57d8fdf26adae6721de14ecae22Nick Pelly        pw.println("getBatteryUsageHint() = " + headset.getBatteryUsageHint());
13386c901db72dbaf57d8fdf26adae6721de14ecae22Nick Pelly
1339105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        headset.close();
13409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1342d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ static int bluezStringToScanMode(boolean pairable, boolean discoverable) {
1343d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (pairable && discoverable)
1344bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            return BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE;
1345d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        else if (pairable && !discoverable)
1346bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            return BluetoothAdapter.SCAN_MODE_CONNECTABLE;
1347d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        else
1348bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            return BluetoothAdapter.SCAN_MODE_NONE;
13499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* package */ static String scanModeToBluezString(int mode) {
13529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        switch (mode) {
1353bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        case BluetoothAdapter.SCAN_MODE_NONE:
13549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "off";
1355bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
13569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "connectable";
1357bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
13589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "discoverable";
13599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return null;
13619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1363d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /*package*/ String getAddressFromObjectPath(String objectPath) {
1364d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String adapterObjectPath = getProperty("ObjectPath");
1365d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (adapterObjectPath == null || objectPath == null) {
1366d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            Log.e(TAG, "getAddressFromObjectPath: AdpaterObjectPath:" + adapterObjectPath +
1367d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                    "  or deviceObjectPath:" + objectPath + " is null");
1368d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return null;
1369d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
1370d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (!objectPath.startsWith(adapterObjectPath)) {
1371d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            Log.e(TAG, "getAddressFromObjectPath: AdpaterObjectPath:" + adapterObjectPath +
1372d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                    "  is not a prefix of deviceObjectPath:" + objectPath +
1373d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                    "bluetoothd crashed ?");
1374d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return null;
1375d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
1376d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String address = objectPath.substring(adapterObjectPath.length());
1377d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (address != null) return address.replace('_', ':');
1378d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1379d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        Log.e(TAG, "getAddressFromObjectPath: Address being returned is null");
1380d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return null;
1381d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
1382d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1383d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /*package*/ String getObjectPathFromAddress(String address) {
1384d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String path = getProperty("ObjectPath");
1385d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (path == null) {
1386d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            Log.e(TAG, "Error: Object Path is null");
1387d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return null;
1388d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
1389d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        path = path + address.replace(":", "_");
1390d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return path;
1391d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
1392d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
13939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static void log(String msg) {
13949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Log.d(TAG, msg);
13959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1396d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1397d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native static void classInitNative();
1398d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native void initializeNativeDataNative();
1399d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setupNativeDataNative();
1400d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean tearDownNativeDataNative();
1401d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native void cleanupNativeDataNative();
1402d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native String getAdapterPathNative();
1403d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1404d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native int isEnabledNative();
1405d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native int enableNative();
1406d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native int disableNative();
1407d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1408d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native Object[] getAdapterPropertiesNative();
1409d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native Object[] getDevicePropertiesNative(String objectPath);
1410d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setAdapterPropertyStringNative(String key, String value);
1411d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setAdapterPropertyIntegerNative(String key, int value);
1412d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setAdapterPropertyBooleanNative(String key, int value);
1413d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1414d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean startDiscoveryNative();
1415d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean stopDiscoveryNative();
1416d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1417d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean createPairedDeviceNative(String address, int timeout_ms);
1418d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean cancelDeviceCreationNative(String address);
1419d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean removeDeviceNative(String objectPath);
1420d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native int getDeviceServiceChannelNative(String objectPath, String uuid,
1421d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            int attributeId);
1422d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1423b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    private native boolean cancelPairingUserInputNative(String address, int nativeData);
1424d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setPinNative(String address, String pin, int nativeData);
1425b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    private native boolean setPasskeyNative(String address, int passkey, int nativeData);
1426b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    private native boolean setPairingConfirmationNative(String address, boolean confirm,
1427b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            int nativeData);
1428efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    private native boolean setDevicePropertyBooleanNative(String objectPath, String key, int value);
14291caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    private native boolean createDeviceNative(String address);
14301caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    private native boolean discoverServicesNative(String objectPath, String pattern);
143110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
14329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1433