BluetoothService.java revision 8c9dd7d8b99e1b064fc064a3c6737eaf179eae68
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * TODO: Move this to
19bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly * java/services/com/android/server/BluetoothService.java
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * and make the contructor package private again.
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @hide
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.server;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
27bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pellyimport android.bluetooth.BluetoothAdapter;
28dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganeshimport android.bluetooth.BluetoothClass;
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.bluetooth.BluetoothDevice;
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.bluetooth.BluetoothHeadset;
3124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pellyimport android.bluetooth.BluetoothSocket;
3210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganeshimport android.bluetooth.BluetoothUuid;
33bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pellyimport android.bluetooth.IBluetooth;
3416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pellyimport android.bluetooth.IBluetoothCallback;
35aef439e6f825c0cb99a2ac08c8207f48b7a9fe10Nick Pellyimport android.os.ParcelUuid;
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.BroadcastReceiver;
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ContentResolver;
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Intent;
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.IntentFilter;
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Binder;
4224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pellyimport android.os.IBinder;
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Handler;
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Message;
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.RemoteException;
46105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Projectimport android.os.ServiceManager;
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemService;
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.Settings;
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log;
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
51d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganeshimport com.android.internal.app.IBatteryStats;
52d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileDescriptor;
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.PrintWriter;
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.UnsupportedEncodingException;
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList;
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Arrays;
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.HashMap;
5916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pellyimport java.util.Iterator;
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Map;
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
62bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pellypublic class BluetoothService extends IBluetooth.Stub {
63bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    private static final String TAG = "BluetoothService";
64db7ae10d6b8e86ff5311512de45afa65a1b0a738Nick Pelly    private static final boolean DBG = false;
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mNativeData;
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private BluetoothEventLoop mEventLoop;
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private IntentFilter mIntentFilter;
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mIsAirplaneSensitive;
70105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private int mBluetoothState;
71997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly    private boolean mRestart = false;  // need to call enable() after disable()
72bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    private boolean mIsDiscovering;
73997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly
74bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    private BluetoothAdapter mAdapter;  // constant after init()
75997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly    private final BondState mBondState = new BondState();  // local cache of bondings
76105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private final IBatteryStats mBatteryStats;
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final Context mContext;
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
82105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private static final int MESSAGE_REGISTER_SDP_RECORDS = 1;
83105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private static final int MESSAGE_FINISH_DISABLE = 2;
841caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    private static final int MESSAGE_UUID_INTENT = 3;
8512835478ee687a493d1b5882e67b6725bd539c26Nick Pelly    private static final int MESSAGE_DISCOVERABLE_TIMEOUT = 4;
861caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
871caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    // The timeout used to sent the UUIDs Intent
881caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    // This timeout should be greater than the page timeout
891caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    private static final int UUID_INTENT_DELAY = 6000;
90105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
9116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    /** Always retrieve RFCOMM channel for these SDP UUIDs */
9216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private static final ParcelUuid[] RFCOMM_UUIDS = {
9316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            BluetoothUuid.Handsfree,
9416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            BluetoothUuid.HSP,
9516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            BluetoothUuid.ObexObjectPush };
9616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
9716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
98bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    private final Map<String, String> mAdapterProperties;
9916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private final HashMap<String, Map<String, String>> mDeviceProperties;
100d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
10116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private final HashMap<String, Map<ParcelUuid, Integer>> mDeviceServiceChannelCache;
10216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private final ArrayList<String> mUuidIntentTracker;
10316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private final HashMap<RemoteService, IBluetoothCallback> mUuidCallbackTracker;
1041caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
10524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private final HashMap<Integer, Integer> mServiceRecordToPid;
10624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
10716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private static class RemoteService {
10816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        public String address;
10916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        public ParcelUuid uuid;
11016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        public RemoteService(String address, ParcelUuid uuid) {
11116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            this.address = address;
11216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            this.uuid = uuid;
11316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
11416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        @Override
11516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        public boolean equals(Object o) {
11616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (o instanceof RemoteService) {
11716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                RemoteService service = (RemoteService)o;
11816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                return address.equals(service.address) && uuid.equals(service.uuid);
11916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
12016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            return false;
12116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
12216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    }
12316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static {
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        classInitNative();
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
128bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    public BluetoothService(Context context) {
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext = context;
130105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
131105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Need to do this in place of:
132105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // mBatteryStats = BatteryStatsService.getService();
133105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Since we can not import BatteryStatsService from here. This class really needs to be
134105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // moved to java/services/com/android/server/
135105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo"));
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        initializeNativeDataNative();
138ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project
139ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project        if (isEnabledNative() == 1) {
140ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project            Log.w(TAG, "Bluetooth daemons already running - runtime restart? ");
141ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project            disableNative();
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
143ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project
144de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        mBluetoothState = BluetoothAdapter.STATE_OFF;
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mIsDiscovering = false;
146bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mAdapterProperties = new HashMap<String, String>();
147bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mDeviceProperties = new HashMap<String, Map<String,String>>();
14810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
14910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        mDeviceServiceChannelCache = new HashMap<String, Map<ParcelUuid, Integer>>();
1501caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        mUuidIntentTracker = new ArrayList<String>();
15116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        mUuidCallbackTracker = new HashMap<RemoteService, IBluetoothCallback>();
15224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        mServiceRecordToPid = new HashMap<Integer, Integer>();
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        registerForAirplaneMode();
154bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    }
155bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly
156bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    public synchronized void initAfterRegistration() {
157f242b7b931898856bcbcb7ec36cacf43098ba544Nick Pelly        mAdapter = BluetoothAdapter.getDefaultAdapter();
158bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mEventLoop = new BluetoothEventLoop(mContext, mAdapter, this);
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void finalize() throws Throwable {
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mIsAirplaneSensitive) {
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mContext.unregisterReceiver(mReceiver);
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            cleanupNativeDataNative();
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super.finalize();
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean isEnabled() {
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1758c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        return isEnabledInternal();
1768c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh    }
1778c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1788c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh    private boolean isEnabledInternal() {
179de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        return mBluetoothState == BluetoothAdapter.STATE_ON;
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
182105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    public int getBluetoothState() {
183105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
184105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        return mBluetoothState;
185105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    }
186105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
187105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Bring down bluetooth and disable BT in settings. Returns true on success.
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean disable() {
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return disable(true);
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Bring down bluetooth. Returns true on success.
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
198e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly     * @param saveSetting If true, persist the new setting
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean disable(boolean saveSetting) {
201e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission");
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
203105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        switch (mBluetoothState) {
204de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_OFF:
205105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return true;
206de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_ON:
207105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            break;
208105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        default:
209105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return false;
210105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mEnableThread != null && mEnableThread.isAlive()) {
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
214de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        setBluetoothState(BluetoothAdapter.STATE_TURNING_OFF);
215bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly        mHandler.removeMessages(MESSAGE_REGISTER_SDP_RECORDS);
216105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
217105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Allow 3 seconds for profiles to gracefully disconnect
218105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // TODO: Introduce a callback mechanism so that each profile can notify
219bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        // BluetoothService when it is done shutting down
220105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mHandler.sendMessageDelayed(
221105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                mHandler.obtainMessage(MESSAGE_FINISH_DISABLE, saveSetting ? 1 : 0, 0), 3000);
222105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        return true;
223105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    }
224105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
225105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
226105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private synchronized void finishDisable(boolean saveSetting) {
227de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        if (mBluetoothState != BluetoothAdapter.STATE_TURNING_OFF) {
228105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return;
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mEventLoop.stop();
231d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        tearDownNativeDataNative();
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        disableNative();
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // mark in progress bondings as cancelled
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (String address : mBondState.listInState(BluetoothDevice.BOND_BONDING)) {
236005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            mBondState.setBondState(address, BluetoothDevice.BOND_NONE,
2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // update mode
241de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        Intent intent = new Intent(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
242de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        intent.putExtra(BluetoothAdapter.EXTRA_SCAN_MODE, BluetoothAdapter.SCAN_MODE_NONE);
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.sendBroadcast(intent, BLUETOOTH_PERM);
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
245105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mIsDiscovering = false;
246bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mAdapterProperties.clear();
24724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        mServiceRecordToPid.clear();
248105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (saveSetting) {
2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            persistBluetoothOnSetting(false);
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
252105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
253de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        setBluetoothState(BluetoothAdapter.STATE_OFF);
254105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
255105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Log bluetooth off to battery stats.
256105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        long ident = Binder.clearCallingIdentity();
257105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        try {
258105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            mBatteryStats.noteBluetoothOff();
259105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        } catch (RemoteException e) {
260105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        } finally {
261105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            Binder.restoreCallingIdentity(ident);
262105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
263997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly
264997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        if (mRestart) {
265997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly            mRestart = false;
266997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly            enable();
267997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        }
2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
270105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    /** Bring up BT and persist BT on in settings */
271105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    public boolean enable() {
272105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        return enable(true);
2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Enable this Bluetooth device, asynchronously.
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * This turns on/off the underlying hardware.
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
279105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project     * @param saveSetting If true, persist the new state of BT in settings
280105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project     * @return True on success (so far)
2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
282105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    public synchronized boolean enable(boolean saveSetting) {
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Airplane mode can prevent Bluetooth radio from being turned on.
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mIsAirplaneSensitive && isAirplaneModeOn()) {
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
290de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        if (mBluetoothState != BluetoothAdapter.STATE_OFF) {
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mEnableThread != null && mEnableThread.isAlive()) {
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
296de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        setBluetoothState(BluetoothAdapter.STATE_TURNING_ON);
297105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mEnableThread = new EnableThread(saveSetting);
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mEnableThread.start();
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
302997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly    /** Forcibly restart Bluetooth if it is on */
303997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly    /* package */ synchronized void restart() {
304de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        if (mBluetoothState != BluetoothAdapter.STATE_ON) {
305997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly            return;
306997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        }
307997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        mRestart = true;
308997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        if (!disable(false)) {
309997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly            mRestart = false;
310997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        }
311d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
312997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly
313105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private synchronized void setBluetoothState(int state) {
314105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        if (state == mBluetoothState) {
315105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return;
316105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
317105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
318105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        if (DBG) log("Bluetooth state " + mBluetoothState + " -> " + state);
319105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
320de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
321de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, mBluetoothState);
322de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        intent.putExtra(BluetoothAdapter.EXTRA_STATE, state);
323105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
324105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
325105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mBluetoothState = state;
326105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
327105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mContext.sendBroadcast(intent, BLUETOOTH_PERM);
328105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    }
329105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final Handler mHandler = new Handler() {
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void handleMessage(Message msg) {
3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            switch (msg.what) {
334105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            case MESSAGE_REGISTER_SDP_RECORDS:
3358c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh                if (!isEnabledInternal()) {
336bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    return;
337bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                }
338bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                // SystemService.start() forks sdptool to register service
339bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                // records. It can fail to register some records if it is
340bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                // forked multiple times in a row, probably because there is
341bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                // some race in sdptool or bluez when operated in parallel.
342bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                // As a workaround, delay 500ms between each fork of sdptool.
343bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                // TODO: Don't fork sdptool in order to regsiter service
344bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                // records, use a DBUS call instead.
345bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                switch (msg.arg1) {
346bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                case 1:
347bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    Log.d(TAG, "Registering hsag record");
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    SystemService.start("hsag");
349bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    mHandler.sendMessageDelayed(
350bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                            mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS, 2, -1), 500);
351bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    break;
352bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                case 2:
353bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    Log.d(TAG, "Registering hfag record");
3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    SystemService.start("hfag");
355bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    mHandler.sendMessageDelayed(
356bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                            mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS, 3, -1), 500);
357bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    break;
358bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                case 3:
359bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    Log.d(TAG, "Registering opush record");
36003c707ab6fc97e99b1603b8d6edc604dbea3cd6fNick Pelly                    SystemService.start("opush");
361bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    mHandler.sendMessageDelayed(
362bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                            mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS, 4, -1), 500);
363bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    break;
364bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                case 4:
365bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    Log.d(TAG, "Registering pbap record");
36667542964876aa7e4216e8f69f21dda68e7463b9aJaikumar Ganesh                    SystemService.start("pbap");
367bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    break;
3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
369105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                break;
370105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            case MESSAGE_FINISH_DISABLE:
371105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                finishDisable(msg.arg1 != 0);
372105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                break;
3731caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            case MESSAGE_UUID_INTENT:
3741caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh                String address = (String)msg.obj;
37516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (address != null) {
3761caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh                    sendUuidIntent(address);
37716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    makeServiceChannelCallbacks(address);
37816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                }
3791caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh                break;
38012835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            case MESSAGE_DISCOVERABLE_TIMEOUT:
38112835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                int mode = msg.arg1;
3828c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh                if (isEnabledInternal()) {
38312835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                    // TODO: Switch back to the previous scan mode
38412835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                    // This is ok for now, because we only use
38512835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                    // CONNECTABLE and CONNECTABLE_DISCOVERABLE
38612835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                    setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE, -1);
38712835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                }
38812835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                break;
3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private EnableThread mEnableThread;
3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private class EnableThread extends Thread {
3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final boolean mSaveSetting;
397105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        public EnableThread(boolean saveSetting) {
3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mSaveSetting = saveSetting;
3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void run() {
4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean res = (enableNative() == 0);
4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (res) {
403b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                int retryCount = 2;
404b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                boolean running = false;
405b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                while ((retryCount-- > 0) && !running) {
406b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    mEventLoop.start();
407105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    // it may take a momement for the other thread to do its
408b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    // thing.  Check periodically for a while.
409b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    int pollCount = 5;
410b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    while ((pollCount-- > 0) && !running) {
411b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                        if (mEventLoop.isEventLoopRunning()) {
412b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                            running = true;
413b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                            break;
414b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                        }
415b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                        try {
416b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                            Thread.sleep(100);
417b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                        } catch (InterruptedException e) {}
418b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    }
419b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                }
420b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                if (!running) {
421b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    log("bt EnableThread giving up");
422b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    res = false;
423b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    disableNative();
424b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                }
4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (res) {
429d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                if (!setupNativeDataNative()) {
430d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                    return;
431d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                }
4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mSaveSetting) {
4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    persistBluetoothOnSetting(true);
4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mIsDiscovering = false;
4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mBondState.loadBondState();
437bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                mHandler.sendMessageDelayed(
438bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                        mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS, 1, -1), 3000);
4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
440105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                // Log bluetooth on to battery stats.
441105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                long ident = Binder.clearCallingIdentity();
442105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                try {
443105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    mBatteryStats.noteBluetoothOn();
444105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                } catch (RemoteException e) {
445105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                } finally {
446105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    Binder.restoreCallingIdentity(ident);
447105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                }
4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
449105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
450105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            mEnableThread = null;
451105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
452105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            setBluetoothState(res ?
453de893f550301a60274e87aa8168225e7a7a42184Nick Pelly                              BluetoothAdapter.STATE_ON :
454de893f550301a60274e87aa8168225e7a7a42184Nick Pelly                              BluetoothAdapter.STATE_OFF);
455105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
456b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            if (res) {
457105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                // Update mode
458d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                String[] propVal = {"Pairable", getProperty("Pairable")};
459d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                mEventLoop.onPropertyChanged(propVal);
460b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            }
461b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project
4625c43f735d94a538dc273c8f859d1100a7cdd5c71Daisuke Miyakawa            if (mIsAirplaneSensitive && isAirplaneModeOn()) {
4635c43f735d94a538dc273c8f859d1100a7cdd5c71Daisuke Miyakawa                disable(false);
4645c43f735d94a538dc273c8f859d1100a7cdd5c71Daisuke Miyakawa            }
4655c43f735d94a538dc273c8f859d1100a7cdd5c71Daisuke Miyakawa
4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void persistBluetoothOnSetting(boolean bluetoothOn) {
4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long origCallerIdentityToken = Binder.clearCallingIdentity();
4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.BLUETOOTH_ON,
4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                bluetoothOn ? 1 : 0);
4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Binder.restoreCallingIdentity(origCallerIdentityToken);
4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* package */ BondState getBondState() {
4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mBondState;
4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** local cache of bonding state.
4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* we keep our own state to track the intermediate state BONDING, which
4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* bluez does not track.
4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * All addreses must be passed in upper case.
4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public class BondState {
4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final HashMap<String, Integer> mState = new HashMap<String, Integer>();
4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final HashMap<String, Integer> mPinAttempt = new HashMap<String, Integer>();
4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final ArrayList<String> mAutoPairingFailures = new ArrayList<String>();
489105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // List of all the vendor_id prefix of Bluetooth addresses for
490105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // which auto pairing is not attempted.
491105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // The following companies are included in the list below:
492105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // ALPS (lexus), Murata (Prius 2007, Nokia 616), TEMIC SDS (Porsche, Audi),
493105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Parrot, Zhongshan General K-mate Electronics, Great Well
494105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Electronics, Flaircomm Electronics, Jatty Electronics, Delphi,
495105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Clarion, Novero, Denso (Lexus, Toyota), Johnson Controls (Acura),
49621d0dca33e0c16c7de5c42bbcdf5a98ec67ead5dJaikumar Ganesh        // Continental Automotive, Harman/Becker, Panasonic/Kyushu Ten,
49721d0dca33e0c16c7de5c42bbcdf5a98ec67ead5dJaikumar Ganesh        // BMW (Motorola PCS)
498482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh        private final ArrayList<String>  mAutoPairingAddressBlacklist =
4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                new ArrayList<String>(Arrays.asList(
500105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                        "00:02:C7", "00:16:FE", "00:19:C1", "00:1B:FB", "00:1E:3D", "00:21:4F",
501105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                        "00:23:06", "00:24:33", "00:A0:79", "00:0E:6D", "00:13:E0", "00:21:E8",
502105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                        "00:60:57", "00:0E:9F", "00:12:1C", "00:18:91", "00:18:96", "00:13:04",
503105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                        "00:16:FD", "00:22:A0", "00:0B:4C", "00:60:6F", "00:23:3D", "00:C0:59",
50421d0dca33e0c16c7de5c42bbcdf5a98ec67ead5dJaikumar Ganesh                        "00:0A:30", "00:1E:AE", "00:1C:D7", "00:80:F0", "00:12:8A"
5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        ));
5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
507482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh        // List of names of Bluetooth devices for which auto pairing should be
508482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh        // disabled.
509738ed80262aa26128924c51f59ffd49e1163eb8dJaikumar Ganesh        private final ArrayList<String> mAutoPairingExactNameBlacklist =
510482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh                new ArrayList<String>(Arrays.asList(
511738ed80262aa26128924c51f59ffd49e1163eb8dJaikumar Ganesh                        "Motorola IHF1000", "i.TechBlueBAND", "X5 Stereo v1.3"));
512738ed80262aa26128924c51f59ffd49e1163eb8dJaikumar Ganesh
513738ed80262aa26128924c51f59ffd49e1163eb8dJaikumar Ganesh        private final ArrayList<String> mAutoPairingPartialNameBlacklist =
514738ed80262aa26128924c51f59ffd49e1163eb8dJaikumar Ganesh                new ArrayList<String>(Arrays.asList(
515738ed80262aa26128924c51f59ffd49e1163eb8dJaikumar Ganesh                        "BMW", "Audi"));
516482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh
5172092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        // If this is an outgoing connection, store the address.
5182092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        // There can be only 1 pending outgoing connection at a time,
5192092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        private String mPendingOutgoingBonding;
5202092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
5212092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        private synchronized void setPendingOutgoingBonding(String address) {
5222092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh            mPendingOutgoingBonding = address;
5232092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        }
5242092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
5252092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        public synchronized String getPendingOutgoingBonding() {
5262092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh            return mPendingOutgoingBonding;
5272092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        }
5282092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized void loadBondState() {
530de893f550301a60274e87aa8168225e7a7a42184Nick Pelly            if (mBluetoothState != BluetoothAdapter.STATE_TURNING_ON) {
5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
533d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            String []bonds = null;
534d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            String val = getProperty("Devices");
535d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            if (val != null) {
536d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                bonds = val.split(",");
537d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            }
5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (bonds == null) {
5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mState.clear();
5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (DBG) log("found " + bonds.length + " bonded devices");
543d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            for (String device : bonds) {
544d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                mState.put(getAddressFromObjectPath(device).toUpperCase(),
545d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                        BluetoothDevice.BOND_BONDED);
5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized void setBondState(String address, int state) {
5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setBondState(address, state, 0);
5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /** reason is ignored unless state == BOND_NOT_BONDED */
5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized void setBondState(String address, int state, int reason) {
5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int oldState = getBondState(address);
5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (oldState == state) {
5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5592092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
5602092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh            // Check if this was an pending outgoing bonding.
5612092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh            // If yes, reset the state.
5622092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh            if (oldState == BluetoothDevice.BOND_BONDING) {
5632092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh                if (address.equals(mPendingOutgoingBonding)) {
5642092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh                    mPendingOutgoingBonding = null;
5652092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh                }
5662092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh            }
5672092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (DBG) log(address + " bond state " + oldState + " -> " + state + " (" +
5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                         reason + ")");
570005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            Intent intent = new Intent(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
571005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
572005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            intent.putExtra(BluetoothDevice.EXTRA_BOND_STATE, state);
573005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            intent.putExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, oldState);
574005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            if (state == BluetoothDevice.BOND_NONE) {
5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (reason <= 0) {
5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Log.w(TAG, "setBondState() called to unbond device, but reason code is " +
5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                          "invalid. Overriding reason code with BOND_RESULT_REMOVED");
5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    reason = BluetoothDevice.UNBOND_REASON_REMOVED;
5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
580005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly                intent.putExtra(BluetoothDevice.EXTRA_REASON, reason);
5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mState.remove(address);
5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mState.put(address, state);
5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mContext.sendBroadcast(intent, BLUETOOTH_PERM);
5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public boolean isAutoPairingBlacklisted(String address) {
590482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh            for (String blacklistAddress : mAutoPairingAddressBlacklist) {
5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (address.startsWith(blacklistAddress)) return true;
5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
593482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh
594482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh            String name = getRemoteName(address);
595482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh            if (name != null) {
596738ed80262aa26128924c51f59ffd49e1163eb8dJaikumar Ganesh                for (String blacklistName : mAutoPairingExactNameBlacklist) {
597738ed80262aa26128924c51f59ffd49e1163eb8dJaikumar Ganesh                    if (name.equals(blacklistName)) return true;
598738ed80262aa26128924c51f59ffd49e1163eb8dJaikumar Ganesh                }
599738ed80262aa26128924c51f59ffd49e1163eb8dJaikumar Ganesh
600738ed80262aa26128924c51f59ffd49e1163eb8dJaikumar Ganesh                for (String blacklistName : mAutoPairingPartialNameBlacklist) {
601738ed80262aa26128924c51f59ffd49e1163eb8dJaikumar Ganesh                    if (name.startsWith(blacklistName)) return true;
602482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh                }
603482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh            }
6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized int getBondState(String address) {
6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Integer state = mState.get(address);
6099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (state == null) {
610005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly                return BluetoothDevice.BOND_NONE;
6119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return state.intValue();
6139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
615e5d93b7ed983f98855555d560faf060836f1a52fJaikumar Ganesh        /*package*/ synchronized String[] listInState(int state) {
6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ArrayList<String> result = new ArrayList<String>(mState.size());
6179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (Map.Entry<String, Integer> e : mState.entrySet()) {
6189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (e.getValue().intValue() == state) {
6199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    result.add(e.getKey());
6209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return result.toArray(new String[result.size()]);
6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized void addAutoPairingFailure(String address) {
6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (!mAutoPairingFailures.contains(address)) {
6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mAutoPairingFailures.add(address);
6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized boolean isAutoPairingAttemptsInProgress(String address) {
6329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return getAttempt(address) != 0;
6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized void clearPinAttempts(String address) {
6369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mPinAttempt.remove(address);
6379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized boolean hasAutoPairingFailed(String address) {
6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mAutoPairingFailures.contains(address);
6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized int getAttempt(String address) {
6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Integer attempt = mPinAttempt.get(address);
6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (attempt == null) {
6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return 0;
6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return attempt.intValue();
6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized void attempt(String address) {
6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Integer attempt = mPinAttempt.get(address);
6539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int newAttempt;
6549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (attempt == null) {
6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                newAttempt = 1;
6569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                newAttempt = attempt.intValue() + 1;
6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mPinAttempt.put(address, new Integer(newAttempt));
6609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static String toBondStateString(int bondState) {
6659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        switch (bondState) {
666005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        case BluetoothDevice.BOND_NONE:
6679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "not bonded";
6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case BluetoothDevice.BOND_BONDING:
6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "bonding";
6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case BluetoothDevice.BOND_BONDED:
6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "bonded";
6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        default:
6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "??????";
6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6779519ce75f15ba287a641166c1b7ed10f2aa73f74Jaikumar Ganesh    /*package*/ synchronized boolean isAdapterPropertiesEmpty() {
6789519ce75f15ba287a641166c1b7ed10f2aa73f74Jaikumar Ganesh        return mAdapterProperties.isEmpty();
6799519ce75f15ba287a641166c1b7ed10f2aa73f74Jaikumar Ganesh    }
6809519ce75f15ba287a641166c1b7ed10f2aa73f74Jaikumar Ganesh
681d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /*package*/synchronized void getAllProperties() {
6828c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
6848c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return;
685bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mAdapterProperties.clear();
686d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
687d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String properties[] = (String [])getAdapterPropertiesNative();
688d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        // The String Array consists of key-value pairs.
689d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (properties == null) {
690d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            Log.e(TAG, "*Error*: GetAdapterProperties returned NULL");
691d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return;
692d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
693d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
6948bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh        for (int i = 0; i < properties.length; i++) {
6958bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            String name = properties[i];
696efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh            String newValue = null;
6978bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            int len;
6988bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            if (name == null) {
6998bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                Log.e(TAG, "Error:Adapter Property at index" + i + "is null");
7008bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                continue;
7018bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            }
7028bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            if (name.equals("Devices")) {
703efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                StringBuilder str = new StringBuilder();
7048bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                len = Integer.valueOf(properties[++i]);
7058bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                for (int j = 0; j < len; j++) {
706efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                    str.append(properties[++i]);
707efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                    str.append(",");
708efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                }
709efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                if (len > 0) {
710efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                    newValue = str.toString();
7118bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                }
7128bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            } else {
7138bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                newValue = properties[++i];
7148bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            }
715bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            mAdapterProperties.put(name, newValue);
716d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
717d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
718d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        // Add adapter object path property.
719d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String adapterPath = getAdapterPathNative();
720d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (adapterPath != null)
721bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            mAdapterProperties.put("ObjectPath", adapterPath + "/dev_");
7229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
724d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ synchronized void setProperty(String name, String value) {
725bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mAdapterProperties.put(name, value);
7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean setName(String name) {
7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
7309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
7319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (name == null) {
7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
734d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setPropertyString("Name", name);
7359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
737d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    //TODO(): setPropertyString, setPropertyInteger, setPropertyBoolean
738d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    // Either have a single property function with Object as the parameter
739d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    // or have a function for each property and then obfuscate in the JNI layer.
740d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    // The following looks dirty.
741d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private boolean setPropertyString(String key, String value) {
7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
7438c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
744d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setAdapterPropertyStringNative(key, value);
7459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
747d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private boolean setPropertyInteger(String key, int value) {
748d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
7498c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
750d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setAdapterPropertyIntegerNative(key, value);
751d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
7529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
753d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private boolean setPropertyBoolean(String key, boolean value) {
754d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
7558c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
756d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setAdapterPropertyBooleanNative(key, value ? 1 : 0);
7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
759d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /**
760d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Set the discoverability window for the device.  A timeout of zero
761d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * makes the device permanently discoverable (if the device is
762d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * discoverable).  Setting the timeout to a nonzero value does not make
763d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * a device discoverable; you need to call setMode() to make the device
764d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * explicitly discoverable.
765d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     *
766d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * @param timeout_s The discoverable timeout in seconds.
767d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     */
768d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized boolean setDiscoverableTimeout(int timeout) {
7699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
7709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
771d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setPropertyInteger("DiscoverableTimeout", timeout);
7729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
77412835478ee687a493d1b5882e67b6725bd539c26Nick Pelly    public synchronized boolean setScanMode(int mode, int duration) {
77518b1e79a123b979d25bfa5d0b0ee5d0382dbd64bNick Pelly        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS,
77618b1e79a123b979d25bfa5d0b0ee5d0382dbd64bNick Pelly                                                "Need WRITE_SECURE_SETTINGS permission");
777de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        boolean pairable = false;
778de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        boolean discoverable = false;
77912835478ee687a493d1b5882e67b6725bd539c26Nick Pelly
780de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        switch (mode) {
781de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.SCAN_MODE_NONE:
78212835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            mHandler.removeMessages(MESSAGE_DISCOVERABLE_TIMEOUT);
783d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            pairable = false;
784d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            discoverable = false;
785de893f550301a60274e87aa8168225e7a7a42184Nick Pelly            break;
786de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
78712835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            mHandler.removeMessages(MESSAGE_DISCOVERABLE_TIMEOUT);
788d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            pairable = true;
789d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            discoverable = false;
790005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            break;
791de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
79212835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            mHandler.removeMessages(MESSAGE_DISCOVERABLE_TIMEOUT);
793d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            pairable = true;
794d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            discoverable = true;
79512835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            Message msg = mHandler.obtainMessage(MESSAGE_DISCOVERABLE_TIMEOUT);
79612835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            mHandler.sendMessageDelayed(msg, duration * 1000);
79712835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            if (DBG) Log.d(TAG, "BT Discoverable for " + duration + " seconds");
798005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            break;
799de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        default:
800de893f550301a60274e87aa8168225e7a7a42184Nick Pelly            Log.w(TAG, "Requested invalid scan mode " + mode);
801de893f550301a60274e87aa8168225e7a7a42184Nick Pelly            return false;
802d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
803d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        setPropertyBoolean("Pairable", pairable);
804d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        setPropertyBoolean("Discoverable", discoverable);
8059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
806d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return true;
8079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
809d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /*package*/ synchronized String getProperty (String name) {
810bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        if (!mAdapterProperties.isEmpty())
811bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            return mAdapterProperties.get(name);
812d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        getAllProperties();
813bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        return mAdapterProperties.get(name);
8149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
816d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized String getAddress() {
817d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
818d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return getProperty("Address");
8199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
821d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized String getName() {
8229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
823d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return getProperty("Name");
8249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
827d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Returns the user-friendly name of a remote device.  This value is
828d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * returned from our local cache, which is updated when onPropertyChange
829d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * event is received.
830d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Do not expect to retrieve the updated remote name immediately after
831d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * changing the name on the remote device.
8329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
833d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * @param address Bluetooth address of remote device.
834d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     *
835d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * @return The user-friendly name of the specified remote device.
8369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
837d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized String getRemoteName(String address) {
838d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
839005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
840d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return null;
841d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
84255929a958bf0e482c8e4d7df3dd75957f1e9d871Jaikumar Ganesh        return getRemoteDeviceProperty(address, "Name");
8439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
8469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Get the discoverability window for the device.  A timeout of zero
8479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * means that the device is permanently discoverable (if the device is
8489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * in the discoverable mode).
8499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
8509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The discoverability window of the device, in seconds.  A negative
8519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         value indicates an error.
8529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
8539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized int getDiscoverableTimeout() {
8549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
855d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String timeout = getProperty("DiscoverableTimeout");
856d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (timeout != null)
857d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh           return Integer.valueOf(timeout);
858d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        else
859d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return -1;
8609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized int getScanMode() {
8639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
8648c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal())
865de893f550301a60274e87aa8168225e7a7a42184Nick Pelly            return BluetoothAdapter.SCAN_MODE_NONE;
866d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
867d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        boolean pairable = getProperty("Pairable").equals("true");
868d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        boolean discoverable = getProperty("Discoverable").equals("true");
869d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return bluezStringToScanMode (pairable, discoverable);
8709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
872d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized boolean startDiscovery() {
8739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
8749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
8758c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
8768c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
877d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return startDiscoveryNative();
8789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
880d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized boolean cancelDiscovery() {
8819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
8829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
8838c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
8848c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
885d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return stopDiscoveryNative();
886d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
887d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
888d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized boolean isDiscovering() {
889d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
890d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return mIsDiscovering;
891d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
892d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
893d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ void setIsDiscovering(boolean isDiscovering) {
894d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mIsDiscovering = isDiscovering;
8959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean createBond(String address) {
8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
9008c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
9018c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
902005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
9039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
9049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        address = address.toUpperCase();
9069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9072092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        if (mBondState.getPendingOutgoingBonding() != null) {
9089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            log("Ignoring createBond(): another device is bonding");
9099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // a different device is currently bonding, fail
9109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
9119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Check for bond state only if we are not performing auto
9149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // pairing exponential back-off attempts.
9159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mBondState.isAutoPairingAttemptsInProgress(address) &&
916005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly                mBondState.getBondState(address) != BluetoothDevice.BOND_NONE) {
9179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            log("Ignoring createBond(): this device is already bonding or bonded");
9189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
9199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
921d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (!createPairedDeviceNative(address, 60000 /* 1 minute */)) {
9229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
9239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9252092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        mBondState.setPendingOutgoingBonding(address);
9269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mBondState.setBondState(address, BluetoothDevice.BOND_BONDING);
9272092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
9289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
9299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean cancelBondProcess(String address) {
9329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
9339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
9348c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
9358c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
936005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
9379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
9389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        address = address.toUpperCase();
9409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mBondState.getBondState(address) != BluetoothDevice.BOND_BONDING) {
9419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
9429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
944005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        mBondState.setBondState(address, BluetoothDevice.BOND_NONE,
9459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
946d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        cancelDeviceCreationNative(address);
9479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
9489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean removeBond(String address) {
9519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
9529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
9538c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
9548c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
955005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
9569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
9579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
958d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return removeDeviceNative(getObjectPathFromAddress(address));
9599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized String[] listBonds() {
9629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
9639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mBondState.listInState(BluetoothDevice.BOND_BONDED);
9649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized int getBondState(String address) {
9679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
968005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
969b24e11baac589fe16426f2d243b460ab84991c7bNick Pelly            return BluetoothDevice.ERROR;
9709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mBondState.getBondState(address.toUpperCase());
9729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9749488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh    /*package*/ boolean isRemoteDeviceInCache(String address) {
975bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        return (mDeviceProperties.get(address) != null);
9769488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh    }
9779488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh
9789488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh    /*package*/ String[] getRemoteDeviceProperties(String address) {
9798c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return null;
9808c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
9819488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh        String objectPath = getObjectPathFromAddress(address);
9829488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh        return (String [])getDevicePropertiesNative(objectPath);
9839488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh    }
9849488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh
985d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /*package*/ synchronized String getRemoteDeviceProperty(String address, String property) {
986bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        Map<String, String> properties = mDeviceProperties.get(address);
987d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (properties != null) {
988d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return properties.get(property);
989d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        } else {
990d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            // Query for remote device properties, again.
991d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            // We will need to reload the cache when we switch Bluetooth on / off
992d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            // or if we crash.
99310eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            if (updateRemoteDevicePropertiesCache(address))
994d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                return getRemoteDeviceProperty(address, property);
9959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
996d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        Log.e(TAG, "getRemoteDeviceProperty: " + property + "not present:" + address);
997d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return null;
9989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
100010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh    /* package */ synchronized boolean updateRemoteDevicePropertiesCache(String address) {
100110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        String[] propValues = getRemoteDeviceProperties(address);
100210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        if (propValues != null) {
100310eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            addRemoteDeviceProperties(address, propValues);
100410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            return true;
100510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        }
100610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        return false;
100710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh    }
100810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
1009d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ synchronized void addRemoteDeviceProperties(String address, String[] properties) {
1010395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh        /*
1011395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh         * We get a DeviceFound signal every time RSSI changes or name changes.
1012395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh         * Don't create a new Map object every time */
1013bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        Map<String, String> propertyValues = mDeviceProperties.get(address);
1014efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh        if (propertyValues == null) {
1015395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh            propertyValues = new HashMap<String, String>();
1016395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh        }
1017395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh
10188bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh        for (int i = 0; i < properties.length; i++) {
10198bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            String name = properties[i];
1020efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh            String newValue = null;
10218bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            int len;
10228bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            if (name == null) {
10238bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                Log.e(TAG, "Error: Remote Device Property at index" + i + "is null");
10248bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                continue;
10258bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            }
10268bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            if (name.equals("UUIDs") || name.equals("Nodes")) {
1027efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                StringBuilder str = new StringBuilder();
10288bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                len = Integer.valueOf(properties[++i]);
10298bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                for (int j = 0; j < len; j++) {
1030efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                    str.append(properties[++i]);
1031efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                    str.append(",");
1032efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                }
1033efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                if (len > 0) {
1034efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                    newValue = str.toString();
10358bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                }
1036d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            } else {
10378bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                newValue = properties[++i];
1038d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            }
1039efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh
10408bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            propertyValues.put(name, newValue);
10419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1042bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mDeviceProperties.put(address, propertyValues);
104310eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
104410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        // We have added a new remote device or updated its properties.
104510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        // Also update the serviceChannel cache.
104610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        updateDeviceServiceChannelCache(address);
10479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1049d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ void removeRemoteDeviceProperties(String address) {
1050bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mDeviceProperties.remove(address);
10519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1053d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ synchronized void setRemoteDeviceProperty(String address, String name,
1054d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                                                              String value) {
1055bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        Map <String, String> propVal = mDeviceProperties.get(address);
1056d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (propVal != null) {
1057d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            propVal.put(name, value);
1058bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            mDeviceProperties.put(address, propVal);
1059d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        } else {
1060d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            Log.e(TAG, "setRemoteDeviceProperty for a device not in cache:" + address);
10619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1065efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * Sets the remote device trust state.
1066efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     *
1067efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * @return boolean to indicate operation success or fail
1068efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     */
1069efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    public synchronized boolean setTrust(String address, boolean value) {
1070005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1071e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly            mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1072e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly                    "Need BLUETOOTH_ADMIN permission");
1073efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            return false;
1074efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        }
1075efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue
10768c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
10778c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1078efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        return setDevicePropertyBooleanNative(getObjectPathFromAddress(address), "Trusted",
1079efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue                value ? 1 : 0);
1080efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    }
1081efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue
1082efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    /**
1083efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * Gets the remote device trust state as boolean.
1084efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * Note: this value may be
1085efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * retrieved from cache if we retrieved the data before *
1086efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     *
1087efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * @return boolean to indicate trust or untrust state
1088efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     */
1089efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    public synchronized boolean getTrustState(String address) {
1090005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1091efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1092efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            return false;
1093efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        }
1094efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue
1095efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        String val = getRemoteDeviceProperty(address, "Trusted");
1096efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        if (val == null) {
1097efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            return false;
1098efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        } else {
1099efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            return val.equals("true") ? true : false;
1100efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        }
1101efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    }
1102efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue
1103efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    /**
1104d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Gets the remote major, minor classes encoded as a 32-bit
11059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * integer.
11069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
11079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Note: this value is retrieved from cache, because we get it during
11089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *       remote-device discovery.
11099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
11109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return 32-bit integer encoding the remote major, minor, and service
11119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         classes.
11129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
11139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized int getRemoteClass(String address) {
1114005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1115ea600ccfb7568f60377c4abc85f56c80af7fdbfcNick Pelly            mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1116ea600ccfb7568f60377c4abc85f56c80af7fdbfcNick Pelly            return BluetoothClass.ERROR;
11179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1118d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String val = getRemoteDeviceProperty(address, "Class");
1119d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (val == null)
1120d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return BluetoothClass.ERROR;
1121d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        else {
1122d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return Integer.valueOf(val);
1123d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
11249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1125d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
11269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1128dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh     * Gets the UUIDs supported by the remote device
11299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1130dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh     * @return array of 128bit ParcelUuids
11319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1132dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh    public synchronized ParcelUuid[] getRemoteUuids(String address) {
11339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1134005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
11359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return null;
11369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11371caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        return getUuidFromCache(address);
11381caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    }
11391caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
11401caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    private ParcelUuid[] getUuidFromCache(String address) {
1141d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String value = getRemoteDeviceProperty(address, "UUIDs");
1142dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        if (value == null) return null;
1143dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh
1144dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        String[] uuidStrings = null;
1145d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        // The UUIDs are stored as a "," separated string.
1146dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        uuidStrings = value.split(",");
1147dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        ParcelUuid[] uuids = new ParcelUuid[uuidStrings.length];
1148dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh
1149dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        for (int i = 0; i < uuidStrings.length; i++) {
1150dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh            uuids[i] = ParcelUuid.fromString(uuidStrings[i]);
1151dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        }
1152d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return uuids;
11539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
115516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    /**
115616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * Connect and fetch new UUID's using SDP.
115716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * The UUID's found are broadcast as intents.
115816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * Optionally takes a uuid and callback to fetch the RFCOMM channel for the
115916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * a given uuid.
116016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * TODO: Don't wait UUID_INTENT_DELAY to broadcast UUID intents on success
116116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * TODO: Don't wait UUID_INTENT_DELAY to handle the failure case for
116216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * callback and broadcast intents.
116316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     */
116416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    public synchronized boolean fetchRemoteUuids(String address, ParcelUuid uuid,
116516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            IBluetoothCallback callback) {
11661caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
11678c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
11688c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
11691caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
11701caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            return false;
11711caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        }
11721caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
117316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        RemoteService service = new RemoteService(address, uuid);
117416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        if (uuid != null && mUuidCallbackTracker.get(service) != null) {
117516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            // An SDP query for this address & uuid is already in progress
117616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            // Do not add this callback for the uuid
117716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            return false;
117816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
117916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
11801caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        if (mUuidIntentTracker.contains(address)) {
11811caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            // An SDP query for this address is already in progress
118216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            // Add this uuid onto the in-progress SDP query
118316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (uuid != null) {
118416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                mUuidCallbackTracker.put(new RemoteService(address, uuid), callback);
118516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
11861caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            return true;
11871caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        }
11881caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
11891caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        boolean ret;
11901caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        if (getBondState(address) == BluetoothDevice.BOND_BONDED) {
11911caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            String path = getObjectPathFromAddress(address);
11921caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            if (path == null) return false;
11931caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
11941caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            // Use an empty string for the UUID pattern
11951caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            ret = discoverServicesNative(path, "");
11961caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        } else {
11971caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            ret = createDeviceNative(address);
11981caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        }
11991caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
12001caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        mUuidIntentTracker.add(address);
120116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        if (uuid != null) {
120216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            mUuidCallbackTracker.put(new RemoteService(address, uuid), callback);
120316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
12041caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
12051caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        Message message = mHandler.obtainMessage(MESSAGE_UUID_INTENT);
12061caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        message.obj = address;
12071caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        mHandler.sendMessageDelayed(message, UUID_INTENT_DELAY);
12081caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        return ret;
12091caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    }
12101caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
12119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1212d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Gets the rfcomm channel associated with the UUID.
121316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * Pulls records from the cache only.
12149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1215d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * @param address Address of the remote device
1216dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh     * @param uuid ParcelUuid of the service attribute
12179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1218d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * @return rfcomm channel associated with the service attribute
121910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh     *         -1 on error
12209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1221dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh    public int getRemoteServiceChannel(String address, ParcelUuid uuid) {
12229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
12238c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return -1;
12248c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1225005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1226b24e11baac589fe16426f2d243b460ab84991c7bNick Pelly            return BluetoothDevice.ERROR;
12279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
122810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        // Check if we are recovering from a crash.
122910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        if (mDeviceProperties.isEmpty()) {
123010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            if (!updateRemoteDevicePropertiesCache(address))
123110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh                return -1;
123210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        }
123310eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
123410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        Map<ParcelUuid, Integer> value = mDeviceServiceChannelCache.get(address);
123510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        if (value != null && value.containsKey(uuid))
123610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            return value.get(uuid);
123710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        return -1;
12389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean setPin(String address, byte[] pin) {
12419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
12429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
12438c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
12448c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
12459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (pin == null || pin.length <= 0 || pin.length > 16 ||
1246005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            !BluetoothAdapter.checkBluetoothAddress(address)) {
12479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
12489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        address = address.toUpperCase();
12509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
12519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (data == null) {
12529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.w(TAG, "setPin(" + address + ") called but no native data available, " +
12539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                  "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
12549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                  " or by bluez.\n");
12559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
12569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // bluez API wants pin as a string
12589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String pinString;
12599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
12609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pinString = new String(pin, "UTF8");
12619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (UnsupportedEncodingException uee) {
12629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.e(TAG, "UTF8 not supported?!?");
12639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
12649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return setPinNative(address, pinString, data.intValue());
12669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1268b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    public synchronized boolean setPasskey(String address, int passkey) {
1269b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1270b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                                                "Need BLUETOOTH_ADMIN permission");
12718c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
12728c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1273005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (passkey < 0 || passkey > 999999 || !BluetoothAdapter.checkBluetoothAddress(address)) {
1274b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            return false;
1275b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        }
1276b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        address = address.toUpperCase();
1277b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
1278b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        if (data == null) {
1279b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            Log.w(TAG, "setPasskey(" + address + ") called but no native data available, " +
1280b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                  "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
1281b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                  " or by bluez.\n");
1282b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            return false;
1283b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        }
1284b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        return setPasskeyNative(address, passkey, data.intValue());
1285b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    }
1286b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh
1287b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    public synchronized boolean setPairingConfirmation(String address, boolean confirm) {
1288b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1289b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                                                "Need BLUETOOTH_ADMIN permission");
12908c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
12918c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1292b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        address = address.toUpperCase();
1293b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
1294b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        if (data == null) {
1295b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            Log.w(TAG, "setPasskey(" + address + ") called but no native data available, " +
1296b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                  "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
1297b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                  " or by bluez.\n");
1298b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            return false;
1299b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        }
1300b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        return setPairingConfirmationNative(address, confirm, data.intValue());
1301b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    }
1302b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh
1303b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    public synchronized boolean cancelPairingUserInput(String address) {
13049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
13059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
13068c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
13078c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1308005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
13099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
13109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1311005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        mBondState.setBondState(address, BluetoothDevice.BOND_NONE,
1312397d8f4f4829a45f4fe7a672cc395466bbc0f442Jaikumar Ganesh                BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
13139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        address = address.toUpperCase();
13149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
13159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (data == null) {
1316b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            Log.w(TAG, "cancelUserInputNative(" + address + ") called but no native data " +
1317b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                "available, ignoring. Maybe the PasskeyAgent Request was already cancelled " +
1318b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                "by the remote or by bluez.\n");
13199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
13209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1321b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        return cancelPairingUserInputNative(address, data.intValue());
13229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13248c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh    /*package*/ void updateDeviceServiceChannelCache(String address) {
132510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        ParcelUuid[] deviceUuids = getRemoteUuids(address);
132610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        // We are storing the rfcomm channel numbers only for the uuids
132710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        // we are interested in.
132810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        int channel;
132916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        if (DBG) log("updateDeviceServiceChannelCache(" + address + ")");
133016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
133116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        ArrayList<ParcelUuid> applicationUuids = new ArrayList();
133216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
133316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        synchronized (this) {
133416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            for (RemoteService service : mUuidCallbackTracker.keySet()) {
133516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (service.address.equals(address)) {
133616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    applicationUuids.add(service.uuid);
133716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                }
133816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
133916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
134010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
134110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        Map <ParcelUuid, Integer> value = new HashMap<ParcelUuid, Integer>();
134216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
134316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        // Retrieve RFCOMM channel for default uuids
134416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        for (ParcelUuid uuid : RFCOMM_UUIDS) {
134510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            if (BluetoothUuid.isUuidPresent(deviceUuids, uuid)) {
134616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                channel = getDeviceServiceChannelNative(getObjectPathFromAddress(address),
134716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        uuid.toString(), 0x0004);
134816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (DBG) log("\tuuid(system): " + uuid + " " + channel);
134910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh                value.put(uuid, channel);
135010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            }
135110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        }
135216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        // Retrieve RFCOMM channel for application requested uuids
135316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        for (ParcelUuid uuid : applicationUuids) {
135416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (BluetoothUuid.isUuidPresent(deviceUuids, uuid)) {
135516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                channel = getDeviceServiceChannelNative(getObjectPathFromAddress(address),
135616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        uuid.toString(), 0x0004);
135716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (DBG) log("\tuuid(application): " + uuid + " " + channel);
135816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                value.put(uuid, channel);
135916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
136016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
136116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
136216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        synchronized (this) {
136316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            // Make application callbacks
136416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            for (Iterator<RemoteService> iter = mUuidCallbackTracker.keySet().iterator();
136516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    iter.hasNext();) {
136616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                RemoteService service = iter.next();
136716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (service.address.equals(address)) {
136816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    channel = -1;
136916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    if (value.get(service.uuid) != null) {
137016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        channel = value.get(service.uuid);
137116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    }
137216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    if (channel != -1) {
137316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        if (DBG) log("Making callback for " + service.uuid + " with result " +
137416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                                channel);
137516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        IBluetoothCallback callback = mUuidCallbackTracker.get(service);
137616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        if (callback != null) {
137716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                            try {
137816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                                callback.onRfcommChannelFound(channel);
137916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                            } catch (RemoteException e) {Log.e(TAG, "", e);}
138016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        }
138116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
138216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        iter.remove();
138316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    }
138416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                }
138516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
138616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
138716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            // Update cache
138816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            mDeviceServiceChannelCache.put(address, value);
138916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
139010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh    }
139110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
139224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    /**
139324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     * b is a handle to a Binder instance, so that this service can be notified
139424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     * for Applications that terminate unexpectedly, to clean there service
139524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     * records
139624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     */
139724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    public synchronized int addRfcommServiceRecord(String serviceName, ParcelUuid uuid,
139824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            int channel, IBinder b) {
13998c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
14008c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return -1;
14018c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
140224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (serviceName == null || uuid == null || channel < 1 ||
140324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                channel > BluetoothSocket.MAX_RFCOMM_CHANNEL) {
140424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            return -1;
140524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
140624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (BluetoothUuid.isUuidPresent(BluetoothUuid.RESERVED_UUIDS, uuid)) {
140724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            Log.w(TAG, "Attempted to register a reserved UUID: " + uuid);
140824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            return -1;
140924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
141024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        int handle = addRfcommServiceRecordNative(serviceName,
141124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                uuid.getUuid().getMostSignificantBits(), uuid.getUuid().getLeastSignificantBits(),
141224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                (short)channel);
141324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (DBG) log("new handle " + Integer.toHexString(handle));
141424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (handle == -1) {
141524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            return -1;
141624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
141724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
141824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        int pid = Binder.getCallingPid();
141924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        mServiceRecordToPid.put(new Integer(handle), new Integer(pid));
142024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        try {
142124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            b.linkToDeath(new Reaper(handle, pid), 0);
142224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        } catch (RemoteException e) {}
142324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        return handle;
142424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    }
142524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
142624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    public void removeServiceRecord(int handle) {
142724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
142824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                                                "Need BLUETOOTH permission");
142924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        checkAndRemoveRecord(handle, Binder.getCallingPid());
143024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    }
143124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
143224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private synchronized void checkAndRemoveRecord(int handle, int pid) {
143324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        Integer handleInt = new Integer(handle);
143424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        Integer owner = mServiceRecordToPid.get(handleInt);
143524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (owner != null && pid == owner.intValue()) {
143624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            if (DBG) log("Removing service record " + Integer.toHexString(handle) + " for pid " +
143724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                    pid);
143824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            mServiceRecordToPid.remove(handleInt);
143924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            removeServiceRecordNative(handle);
144024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
144124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    }
144224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
144324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private class Reaper implements IBinder.DeathRecipient {
144424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        int pid;
144524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        int handle;
144624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        Reaper(int handle, int pid) {
144724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            this.pid = pid;
144824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            this.handle = handle;
144924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
145024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        public void binderDied() {
145124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            synchronized (BluetoothService.this) {
145224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                if (DBG) log("Tracked app " + pid + " died");
145324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                checkAndRemoveRecord(handle, pid);
145424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            }
145524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
145624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    }
145724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
14589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
14599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
14609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onReceive(Context context, Intent intent) {
14619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String action = intent.getAction();
14629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
14639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ContentResolver resolver = context.getContentResolver();
14649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Query the airplane mode from Settings.System just to make sure that
14659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // some random app is not sending this intent and disabling bluetooth
14669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                boolean enabled = !isAirplaneModeOn();
14679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // If bluetooth is currently expected to be on, then enable or disable bluetooth
14689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (Settings.Secure.getInt(resolver, Settings.Secure.BLUETOOTH_ON, 0) > 0) {
14699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (enabled) {
1470105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                        enable(false);
14719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } else {
14729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        disable(false);
14739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
14749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
14759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
14769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
14779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
14789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void registerForAirplaneMode() {
14809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String airplaneModeRadios = Settings.System.getString(mContext.getContentResolver(),
14819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Settings.System.AIRPLANE_MODE_RADIOS);
14829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mIsAirplaneSensitive = airplaneModeRadios == null
14839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ? true : airplaneModeRadios.contains(Settings.System.RADIO_BLUETOOTH);
14849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mIsAirplaneSensitive) {
14859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mIntentFilter = new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
14869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mContext.registerReceiver(mReceiver, mIntentFilter);
14879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
14889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* Returns true if airplane mode is currently on */
14919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final boolean isAirplaneModeOn() {
14929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return Settings.System.getInt(mContext.getContentResolver(),
14939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Settings.System.AIRPLANE_MODE_ON, 0) == 1;
14949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14961caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    /* Broadcast the Uuid intent */
14971caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    /*package*/ synchronized void sendUuidIntent(String address) {
14986179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh        ParcelUuid[] uuid = getUuidFromCache(address);
14996179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh        Intent intent = new Intent(BluetoothDevice.ACTION_UUID);
15002d3b98d868cda30535505b2a2fba47aa1c9c052bJaikumar Ganesh        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
15016179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh        intent.putExtra(BluetoothDevice.EXTRA_UUID, uuid);
15026179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh        mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
15031caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
15046179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh        if (mUuidIntentTracker.contains(address))
15051caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            mUuidIntentTracker.remove(address);
150616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
150716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    }
150816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
150916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    /*package*/ synchronized void makeServiceChannelCallbacks(String address) {
151016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        for (Iterator<RemoteService> iter = mUuidCallbackTracker.keySet().iterator();
151116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                iter.hasNext();) {
151216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            RemoteService service = iter.next();
151316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (service.address.equals(address)) {
151416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (DBG) log("Cleaning up failed UUID channel lookup: " + service.address +
151516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        " " + service.uuid);
151616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                IBluetoothCallback callback = mUuidCallbackTracker.get(service);
151716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (callback != null) {
151816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    try {
151916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        callback.onRfcommChannelFound(-1);
152016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    } catch (RemoteException e) {Log.e(TAG, "", e);}
152116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                }
152216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
152316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                iter.remove();
152416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
152516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
15261caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    }
15271caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
15289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
15299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1530105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        switch(mBluetoothState) {
1531de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_OFF:
153224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            pw.println("Bluetooth OFF\n");
1533105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return;
1534de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_TURNING_ON:
153524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            pw.println("Bluetooth TURNING ON\n");
1536105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return;
1537de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_TURNING_OFF:
153824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            pw.println("Bluetooth TURNING OFF\n");
1539105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return;
1540de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_ON:
154124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            pw.println("Bluetooth ON\n");
1542105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
1543105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
154424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("mIsAirplaneSensitive = " + mIsAirplaneSensitive);
154524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
154624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("Local address = " + getAddress());
154724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("Local name = " + getName());
154824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("isDiscovering() = " + isDiscovering());
1549105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
1550105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        BluetoothHeadset headset = new BluetoothHeadset(mContext, null);
1551105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
1552105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        pw.println("\n--Known devices--");
1553bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        for (String address : mDeviceProperties.keySet()) {
15541eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly            int bondState = mBondState.getBondState(address);
1555105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            pw.printf("%s %10s (%d) %s\n", address,
15561eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly                       toBondStateString(bondState),
1557105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                       mBondState.getAttempt(address),
1558105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                       getRemoteName(address));
155924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
156024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            Map<ParcelUuid, Integer> uuidChannels = mDeviceServiceChannelCache.get(address);
156124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            if (uuidChannels == null) {
156224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                pw.println("\tuuids = null");
156324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            } else {
156424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                for (ParcelUuid uuid : uuidChannels.keySet()) {
156524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                    Integer channel = uuidChannels.get(uuid);
156624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                    if (channel == null) {
156724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                        pw.println("\t" + uuid);
156824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                    } else {
156924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                        pw.println("\t" + uuid + " RFCOMM channel = " + channel);
15701eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly                    }
15711eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly                }
15721eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly            }
157316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            for (RemoteService service : mUuidCallbackTracker.keySet()) {
157416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (service.address.equals(address)) {
157516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    pw.println("\tPENDING CALLBACK: " + service.uuid);
157616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                }
157716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
1578105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
1579105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
1580d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String value = getProperty("Devices");
15811eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly        String[] devicesObjectPath = null;
1582d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (value != null) {
1583d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            devicesObjectPath = value.split(",");
1584d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
1585105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        pw.println("\n--ACL connected devices--");
158624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (devicesObjectPath != null) {
158724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            for (String device : devicesObjectPath) {
158824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                pw.println(getAddressFromObjectPath(device));
158924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            }
1590105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
1591105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
1592105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Rather not do this from here, but no-where else and I need this
1593105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // dump
1594105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        pw.println("\n--Headset Service--");
1595105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        switch (headset.getState()) {
1596105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        case BluetoothHeadset.STATE_DISCONNECTED:
1597105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            pw.println("getState() = STATE_DISCONNECTED");
1598105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            break;
1599105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        case BluetoothHeadset.STATE_CONNECTING:
1600105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            pw.println("getState() = STATE_CONNECTING");
1601105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            break;
1602105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        case BluetoothHeadset.STATE_CONNECTED:
1603105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            pw.println("getState() = STATE_CONNECTED");
1604105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            break;
1605105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        case BluetoothHeadset.STATE_ERROR:
1606105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            pw.println("getState() = STATE_ERROR");
1607105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            break;
1608105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
16096c901db72dbaf57d8fdf26adae6721de14ecae22Nick Pelly
161024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("\ngetCurrentHeadset() = " + headset.getCurrentHeadset());
161124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("getBatteryUsageHint() = " + headset.getBatteryUsageHint());
1612105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        headset.close();
161324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("\n--Application Service Records--");
161424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        for (Integer handle : mServiceRecordToPid.keySet()) {
161524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            Integer pid = mServiceRecordToPid.get(handle);
161624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            pw.println("\tpid " + pid + " handle " + Integer.toHexString(handle));
161724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
16189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
16199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1620d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ static int bluezStringToScanMode(boolean pairable, boolean discoverable) {
1621d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (pairable && discoverable)
1622bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            return BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE;
1623d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        else if (pairable && !discoverable)
1624bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            return BluetoothAdapter.SCAN_MODE_CONNECTABLE;
1625d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        else
1626bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            return BluetoothAdapter.SCAN_MODE_NONE;
16279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
16289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* package */ static String scanModeToBluezString(int mode) {
16309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        switch (mode) {
1631bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        case BluetoothAdapter.SCAN_MODE_NONE:
16329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "off";
1633bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
16349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "connectable";
1635bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
16369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "discoverable";
16379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
16389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return null;
16399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
16409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1641d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /*package*/ String getAddressFromObjectPath(String objectPath) {
1642d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String adapterObjectPath = getProperty("ObjectPath");
1643d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (adapterObjectPath == null || objectPath == null) {
1644d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            Log.e(TAG, "getAddressFromObjectPath: AdpaterObjectPath:" + adapterObjectPath +
1645d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                    "  or deviceObjectPath:" + objectPath + " is null");
1646d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return null;
1647d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
1648d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (!objectPath.startsWith(adapterObjectPath)) {
1649d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            Log.e(TAG, "getAddressFromObjectPath: AdpaterObjectPath:" + adapterObjectPath +
1650d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                    "  is not a prefix of deviceObjectPath:" + objectPath +
1651d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                    "bluetoothd crashed ?");
1652d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return null;
1653d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
1654d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String address = objectPath.substring(adapterObjectPath.length());
1655d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (address != null) return address.replace('_', ':');
1656d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1657d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        Log.e(TAG, "getAddressFromObjectPath: Address being returned is null");
1658d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return null;
1659d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
1660d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1661d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /*package*/ String getObjectPathFromAddress(String address) {
1662d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String path = getProperty("ObjectPath");
1663d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (path == null) {
1664d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            Log.e(TAG, "Error: Object Path is null");
1665d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return null;
1666d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
1667d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        path = path + address.replace(":", "_");
1668d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return path;
1669d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
1670d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
16719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static void log(String msg) {
16729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Log.d(TAG, msg);
16739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1674d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1675d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native static void classInitNative();
1676d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native void initializeNativeDataNative();
1677d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setupNativeDataNative();
1678d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean tearDownNativeDataNative();
1679d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native void cleanupNativeDataNative();
1680d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native String getAdapterPathNative();
1681d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1682d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native int isEnabledNative();
1683d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native int enableNative();
1684d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native int disableNative();
1685d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1686d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native Object[] getAdapterPropertiesNative();
1687d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native Object[] getDevicePropertiesNative(String objectPath);
1688d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setAdapterPropertyStringNative(String key, String value);
1689d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setAdapterPropertyIntegerNative(String key, int value);
1690d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setAdapterPropertyBooleanNative(String key, int value);
1691d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1692d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean startDiscoveryNative();
1693d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean stopDiscoveryNative();
1694d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1695d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean createPairedDeviceNative(String address, int timeout_ms);
1696d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean cancelDeviceCreationNative(String address);
1697d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean removeDeviceNative(String objectPath);
1698d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native int getDeviceServiceChannelNative(String objectPath, String uuid,
1699d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            int attributeId);
1700d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1701b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    private native boolean cancelPairingUserInputNative(String address, int nativeData);
1702d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setPinNative(String address, String pin, int nativeData);
1703b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    private native boolean setPasskeyNative(String address, int passkey, int nativeData);
1704b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    private native boolean setPairingConfirmationNative(String address, boolean confirm,
1705b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            int nativeData);
170624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private native boolean setDevicePropertyBooleanNative(String objectPath, String key,
170724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            int value);
17081caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    private native boolean createDeviceNative(String address);
170916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    /*package*/ native boolean discoverServicesNative(String objectPath, String pattern);
171010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
171124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private native int addRfcommServiceRecordNative(String name, long uuidMsb, long uuidLsb,
171224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            short channel);
171324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private native boolean removeServiceRecordNative(int handle);
17149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1715