BluetoothService.java revision 738ed80262aa26128924c51f59ffd49e1163eb8d
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");
175de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        return mBluetoothState == BluetoothAdapter.STATE_ON;
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
178105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    public int getBluetoothState() {
179105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
180105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        return mBluetoothState;
181105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    }
182105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
183105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Bring down bluetooth and disable BT in settings. Returns true on success.
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean disable() {
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return disable(true);
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Bring down bluetooth. Returns true on success.
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
194e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly     * @param saveSetting If true, persist the new setting
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean disable(boolean saveSetting) {
197e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission");
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
199105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        switch (mBluetoothState) {
200de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_OFF:
201105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return true;
202de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_ON:
203105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            break;
204105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        default:
205105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return false;
206105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mEnableThread != null && mEnableThread.isAlive()) {
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
210de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        setBluetoothState(BluetoothAdapter.STATE_TURNING_OFF);
211bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly        mHandler.removeMessages(MESSAGE_REGISTER_SDP_RECORDS);
212105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
213105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Allow 3 seconds for profiles to gracefully disconnect
214105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // TODO: Introduce a callback mechanism so that each profile can notify
215bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        // BluetoothService when it is done shutting down
216105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mHandler.sendMessageDelayed(
217105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                mHandler.obtainMessage(MESSAGE_FINISH_DISABLE, saveSetting ? 1 : 0, 0), 3000);
218105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        return true;
219105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    }
220105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
221105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
222105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private synchronized void finishDisable(boolean saveSetting) {
223de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        if (mBluetoothState != BluetoothAdapter.STATE_TURNING_OFF) {
224105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return;
2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mEventLoop.stop();
227d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        tearDownNativeDataNative();
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        disableNative();
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // mark in progress bondings as cancelled
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (String address : mBondState.listInState(BluetoothDevice.BOND_BONDING)) {
232005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            mBondState.setBondState(address, BluetoothDevice.BOND_NONE,
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // update mode
237de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        Intent intent = new Intent(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
238de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        intent.putExtra(BluetoothAdapter.EXTRA_SCAN_MODE, BluetoothAdapter.SCAN_MODE_NONE);
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.sendBroadcast(intent, BLUETOOTH_PERM);
2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
241105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mIsDiscovering = false;
242bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mAdapterProperties.clear();
24324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        mServiceRecordToPid.clear();
244105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (saveSetting) {
2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            persistBluetoothOnSetting(false);
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
248105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
249de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        setBluetoothState(BluetoothAdapter.STATE_OFF);
250105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
251105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Log bluetooth off to battery stats.
252105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        long ident = Binder.clearCallingIdentity();
253105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        try {
254105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            mBatteryStats.noteBluetoothOff();
255105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        } catch (RemoteException e) {
256105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        } finally {
257105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            Binder.restoreCallingIdentity(ident);
258105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
259997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly
260997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        if (mRestart) {
261997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly            mRestart = false;
262997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly            enable();
263997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        }
2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
266105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    /** Bring up BT and persist BT on in settings */
267105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    public boolean enable() {
268105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        return enable(true);
2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Enable this Bluetooth device, asynchronously.
2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * This turns on/off the underlying hardware.
2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
275105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project     * @param saveSetting If true, persist the new state of BT in settings
276105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project     * @return True on success (so far)
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
278105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    public synchronized boolean enable(boolean saveSetting) {
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Airplane mode can prevent Bluetooth radio from being turned on.
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mIsAirplaneSensitive && isAirplaneModeOn()) {
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
286de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        if (mBluetoothState != BluetoothAdapter.STATE_OFF) {
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mEnableThread != null && mEnableThread.isAlive()) {
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
292de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        setBluetoothState(BluetoothAdapter.STATE_TURNING_ON);
293105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mEnableThread = new EnableThread(saveSetting);
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mEnableThread.start();
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
298997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly    /** Forcibly restart Bluetooth if it is on */
299997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly    /* package */ synchronized void restart() {
300de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        if (mBluetoothState != BluetoothAdapter.STATE_ON) {
301997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly            return;
302997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        }
303997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        mRestart = true;
304997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        if (!disable(false)) {
305997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly            mRestart = false;
306997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        }
307d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
308997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly
309105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private synchronized void setBluetoothState(int state) {
310105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        if (state == mBluetoothState) {
311105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return;
312105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
313105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
314105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        if (DBG) log("Bluetooth state " + mBluetoothState + " -> " + state);
315105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
316de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
317de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, mBluetoothState);
318de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        intent.putExtra(BluetoothAdapter.EXTRA_STATE, state);
319105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
320105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
321105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mBluetoothState = state;
322105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
323105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mContext.sendBroadcast(intent, BLUETOOTH_PERM);
324105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    }
325105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final Handler mHandler = new Handler() {
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void handleMessage(Message msg) {
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            switch (msg.what) {
330105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            case MESSAGE_REGISTER_SDP_RECORDS:
331bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                if (!isEnabled()) {
332bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    return;
333bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                }
334bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                // SystemService.start() forks sdptool to register service
335bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                // records. It can fail to register some records if it is
336bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                // forked multiple times in a row, probably because there is
337bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                // some race in sdptool or bluez when operated in parallel.
338bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                // As a workaround, delay 500ms between each fork of sdptool.
339bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                // TODO: Don't fork sdptool in order to regsiter service
340bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                // records, use a DBUS call instead.
341bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                switch (msg.arg1) {
342bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                case 1:
343bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    Log.d(TAG, "Registering hsag record");
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    SystemService.start("hsag");
345bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    mHandler.sendMessageDelayed(
346bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                            mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS, 2, -1), 500);
347bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    break;
348bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                case 2:
349bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    Log.d(TAG, "Registering hfag record");
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    SystemService.start("hfag");
351bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    mHandler.sendMessageDelayed(
352bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                            mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS, 3, -1), 500);
353bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    break;
354bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                case 3:
355bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    Log.d(TAG, "Registering opush record");
35603c707ab6fc97e99b1603b8d6edc604dbea3cd6fNick Pelly                    SystemService.start("opush");
357bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    mHandler.sendMessageDelayed(
358bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                            mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS, 4, -1), 500);
359bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    break;
360bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                case 4:
361bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    Log.d(TAG, "Registering pbap record");
36267542964876aa7e4216e8f69f21dda68e7463b9aJaikumar Ganesh                    SystemService.start("pbap");
363bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    break;
3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
365105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                break;
366105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            case MESSAGE_FINISH_DISABLE:
367105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                finishDisable(msg.arg1 != 0);
368105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                break;
3691caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            case MESSAGE_UUID_INTENT:
3701caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh                String address = (String)msg.obj;
37116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (address != null) {
3721caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh                    sendUuidIntent(address);
37316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    makeServiceChannelCallbacks(address);
37416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                }
3751caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh                break;
37612835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            case MESSAGE_DISCOVERABLE_TIMEOUT:
37712835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                int mode = msg.arg1;
37812835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                if (isEnabled()) {
37912835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                    // TODO: Switch back to the previous scan mode
38012835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                    // This is ok for now, because we only use
38112835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                    // CONNECTABLE and CONNECTABLE_DISCOVERABLE
38212835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                    setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE, -1);
38312835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                }
38412835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                break;
3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private EnableThread mEnableThread;
3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private class EnableThread extends Thread {
3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final boolean mSaveSetting;
393105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        public EnableThread(boolean saveSetting) {
3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mSaveSetting = saveSetting;
3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void run() {
3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean res = (enableNative() == 0);
3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (res) {
399b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                int retryCount = 2;
400b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                boolean running = false;
401b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                while ((retryCount-- > 0) && !running) {
402b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    mEventLoop.start();
403105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    // it may take a momement for the other thread to do its
404b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    // thing.  Check periodically for a while.
405b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    int pollCount = 5;
406b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    while ((pollCount-- > 0) && !running) {
407b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                        if (mEventLoop.isEventLoopRunning()) {
408b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                            running = true;
409b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                            break;
410b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                        }
411b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                        try {
412b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                            Thread.sleep(100);
413b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                        } catch (InterruptedException e) {}
414b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    }
415b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                }
416b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                if (!running) {
417b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    log("bt EnableThread giving up");
418b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    res = false;
419b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    disableNative();
420b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                }
4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (res) {
425d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                if (!setupNativeDataNative()) {
426d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                    return;
427d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                }
4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mSaveSetting) {
4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    persistBluetoothOnSetting(true);
4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mIsDiscovering = false;
4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mBondState.loadBondState();
433bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                mHandler.sendMessageDelayed(
434bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                        mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS, 1, -1), 3000);
4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
436105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                // Log bluetooth on to battery stats.
437105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                long ident = Binder.clearCallingIdentity();
438105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                try {
439105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    mBatteryStats.noteBluetoothOn();
440105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                } catch (RemoteException e) {
441105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                } finally {
442105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    Binder.restoreCallingIdentity(ident);
443105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                }
4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
445105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
446105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            mEnableThread = null;
447105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
448105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            setBluetoothState(res ?
449de893f550301a60274e87aa8168225e7a7a42184Nick Pelly                              BluetoothAdapter.STATE_ON :
450de893f550301a60274e87aa8168225e7a7a42184Nick Pelly                              BluetoothAdapter.STATE_OFF);
451105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
452b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            if (res) {
453105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                // Update mode
454d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                String[] propVal = {"Pairable", getProperty("Pairable")};
455d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                mEventLoop.onPropertyChanged(propVal);
456b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            }
457b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project
4585c43f735d94a538dc273c8f859d1100a7cdd5c71Daisuke Miyakawa            if (mIsAirplaneSensitive && isAirplaneModeOn()) {
4595c43f735d94a538dc273c8f859d1100a7cdd5c71Daisuke Miyakawa                disable(false);
4605c43f735d94a538dc273c8f859d1100a7cdd5c71Daisuke Miyakawa            }
4615c43f735d94a538dc273c8f859d1100a7cdd5c71Daisuke Miyakawa
4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void persistBluetoothOnSetting(boolean bluetoothOn) {
4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long origCallerIdentityToken = Binder.clearCallingIdentity();
4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.BLUETOOTH_ON,
4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                bluetoothOn ? 1 : 0);
4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Binder.restoreCallingIdentity(origCallerIdentityToken);
4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* package */ BondState getBondState() {
4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mBondState;
4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** local cache of bonding state.
4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* we keep our own state to track the intermediate state BONDING, which
4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* bluez does not track.
4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * All addreses must be passed in upper case.
4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public class BondState {
4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final HashMap<String, Integer> mState = new HashMap<String, Integer>();
4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final HashMap<String, Integer> mPinAttempt = new HashMap<String, Integer>();
4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final ArrayList<String> mAutoPairingFailures = new ArrayList<String>();
485105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // List of all the vendor_id prefix of Bluetooth addresses for
486105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // which auto pairing is not attempted.
487105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // The following companies are included in the list below:
488105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // ALPS (lexus), Murata (Prius 2007, Nokia 616), TEMIC SDS (Porsche, Audi),
489105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Parrot, Zhongshan General K-mate Electronics, Great Well
490105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Electronics, Flaircomm Electronics, Jatty Electronics, Delphi,
491105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Clarion, Novero, Denso (Lexus, Toyota), Johnson Controls (Acura),
49221d0dca33e0c16c7de5c42bbcdf5a98ec67ead5dJaikumar Ganesh        // Continental Automotive, Harman/Becker, Panasonic/Kyushu Ten,
49321d0dca33e0c16c7de5c42bbcdf5a98ec67ead5dJaikumar Ganesh        // BMW (Motorola PCS)
494482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh        private final ArrayList<String>  mAutoPairingAddressBlacklist =
4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                new ArrayList<String>(Arrays.asList(
496105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                        "00:02:C7", "00:16:FE", "00:19:C1", "00:1B:FB", "00:1E:3D", "00:21:4F",
497105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                        "00:23:06", "00:24:33", "00:A0:79", "00:0E:6D", "00:13:E0", "00:21:E8",
498105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                        "00:60:57", "00:0E:9F", "00:12:1C", "00:18:91", "00:18:96", "00:13:04",
499105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                        "00:16:FD", "00:22:A0", "00:0B:4C", "00:60:6F", "00:23:3D", "00:C0:59",
50021d0dca33e0c16c7de5c42bbcdf5a98ec67ead5dJaikumar Ganesh                        "00:0A:30", "00:1E:AE", "00:1C:D7", "00:80:F0", "00:12:8A"
5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        ));
5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
503482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh        // List of names of Bluetooth devices for which auto pairing should be
504482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh        // disabled.
505738ed80262aa26128924c51f59ffd49e1163eb8dJaikumar Ganesh        private final ArrayList<String> mAutoPairingExactNameBlacklist =
506482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh                new ArrayList<String>(Arrays.asList(
507738ed80262aa26128924c51f59ffd49e1163eb8dJaikumar Ganesh                        "Motorola IHF1000", "i.TechBlueBAND", "X5 Stereo v1.3"));
508738ed80262aa26128924c51f59ffd49e1163eb8dJaikumar Ganesh
509738ed80262aa26128924c51f59ffd49e1163eb8dJaikumar Ganesh        private final ArrayList<String> mAutoPairingPartialNameBlacklist =
510738ed80262aa26128924c51f59ffd49e1163eb8dJaikumar Ganesh                new ArrayList<String>(Arrays.asList(
511738ed80262aa26128924c51f59ffd49e1163eb8dJaikumar Ganesh                        "BMW", "Audi"));
512482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh
5132092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        // If this is an outgoing connection, store the address.
5142092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        // There can be only 1 pending outgoing connection at a time,
5152092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        private String mPendingOutgoingBonding;
5162092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
5172092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        private synchronized void setPendingOutgoingBonding(String address) {
5182092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh            mPendingOutgoingBonding = address;
5192092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        }
5202092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
5212092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        public synchronized String getPendingOutgoingBonding() {
5222092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh            return mPendingOutgoingBonding;
5232092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        }
5242092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized void loadBondState() {
526de893f550301a60274e87aa8168225e7a7a42184Nick Pelly            if (mBluetoothState != BluetoothAdapter.STATE_TURNING_ON) {
5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
529d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            String []bonds = null;
530d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            String val = getProperty("Devices");
531d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            if (val != null) {
532d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                bonds = val.split(",");
533d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            }
5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (bonds == null) {
5359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mState.clear();
5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (DBG) log("found " + bonds.length + " bonded devices");
539d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            for (String device : bonds) {
540d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                mState.put(getAddressFromObjectPath(device).toUpperCase(),
541d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                        BluetoothDevice.BOND_BONDED);
5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized void setBondState(String address, int state) {
5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setBondState(address, state, 0);
5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /** reason is ignored unless state == BOND_NOT_BONDED */
5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized void setBondState(String address, int state, int reason) {
5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int oldState = getBondState(address);
5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (oldState == state) {
5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5552092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
5562092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh            // Check if this was an pending outgoing bonding.
5572092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh            // If yes, reset the state.
5582092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh            if (oldState == BluetoothDevice.BOND_BONDING) {
5592092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh                if (address.equals(mPendingOutgoingBonding)) {
5602092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh                    mPendingOutgoingBonding = null;
5612092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh                }
5622092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh            }
5632092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (DBG) log(address + " bond state " + oldState + " -> " + state + " (" +
5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                         reason + ")");
566005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            Intent intent = new Intent(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
567005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
568005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            intent.putExtra(BluetoothDevice.EXTRA_BOND_STATE, state);
569005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            intent.putExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, oldState);
570005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            if (state == BluetoothDevice.BOND_NONE) {
5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (reason <= 0) {
5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Log.w(TAG, "setBondState() called to unbond device, but reason code is " +
5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                          "invalid. Overriding reason code with BOND_RESULT_REMOVED");
5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    reason = BluetoothDevice.UNBOND_REASON_REMOVED;
5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
576005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly                intent.putExtra(BluetoothDevice.EXTRA_REASON, reason);
5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mState.remove(address);
5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mState.put(address, state);
5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mContext.sendBroadcast(intent, BLUETOOTH_PERM);
5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public boolean isAutoPairingBlacklisted(String address) {
586482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh            for (String blacklistAddress : mAutoPairingAddressBlacklist) {
5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (address.startsWith(blacklistAddress)) return true;
5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
589482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh
590482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh            String name = getRemoteName(address);
591482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh            if (name != null) {
592738ed80262aa26128924c51f59ffd49e1163eb8dJaikumar Ganesh                for (String blacklistName : mAutoPairingExactNameBlacklist) {
593738ed80262aa26128924c51f59ffd49e1163eb8dJaikumar Ganesh                    if (name.equals(blacklistName)) return true;
594738ed80262aa26128924c51f59ffd49e1163eb8dJaikumar Ganesh                }
595738ed80262aa26128924c51f59ffd49e1163eb8dJaikumar Ganesh
596738ed80262aa26128924c51f59ffd49e1163eb8dJaikumar Ganesh                for (String blacklistName : mAutoPairingPartialNameBlacklist) {
597738ed80262aa26128924c51f59ffd49e1163eb8dJaikumar Ganesh                    if (name.startsWith(blacklistName)) return true;
598482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh                }
599482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh            }
6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized int getBondState(String address) {
6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Integer state = mState.get(address);
6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (state == null) {
606005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly                return BluetoothDevice.BOND_NONE;
6079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return state.intValue();
6099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
611e5d93b7ed983f98855555d560faf060836f1a52fJaikumar Ganesh        /*package*/ synchronized String[] listInState(int state) {
6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ArrayList<String> result = new ArrayList<String>(mState.size());
6139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (Map.Entry<String, Integer> e : mState.entrySet()) {
6149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (e.getValue().intValue() == state) {
6159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    result.add(e.getKey());
6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
6179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return result.toArray(new String[result.size()]);
6199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized void addAutoPairingFailure(String address) {
6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (!mAutoPairingFailures.contains(address)) {
6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mAutoPairingFailures.add(address);
6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized boolean isAutoPairingAttemptsInProgress(String address) {
6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return getAttempt(address) != 0;
6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized void clearPinAttempts(String address) {
6329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mPinAttempt.remove(address);
6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized boolean hasAutoPairingFailed(String address) {
6369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mAutoPairingFailures.contains(address);
6379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized int getAttempt(String address) {
6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Integer attempt = mPinAttempt.get(address);
6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (attempt == null) {
6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return 0;
6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return attempt.intValue();
6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized void attempt(String address) {
6489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Integer attempt = mPinAttempt.get(address);
6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int newAttempt;
6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (attempt == null) {
6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                newAttempt = 1;
6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
6539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                newAttempt = attempt.intValue() + 1;
6549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mPinAttempt.put(address, new Integer(newAttempt));
6569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static String toBondStateString(int bondState) {
6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        switch (bondState) {
662005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        case BluetoothDevice.BOND_NONE:
6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "not bonded";
6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case BluetoothDevice.BOND_BONDING:
6659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "bonding";
6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case BluetoothDevice.BOND_BONDED:
6679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "bonded";
6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        default:
6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "??????";
6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6739519ce75f15ba287a641166c1b7ed10f2aa73f74Jaikumar Ganesh    /*package*/ synchronized boolean isAdapterPropertiesEmpty() {
6749519ce75f15ba287a641166c1b7ed10f2aa73f74Jaikumar Ganesh        return mAdapterProperties.isEmpty();
6759519ce75f15ba287a641166c1b7ed10f2aa73f74Jaikumar Ganesh    }
6769519ce75f15ba287a641166c1b7ed10f2aa73f74Jaikumar Ganesh
677d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /*package*/synchronized void getAllProperties() {
6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
679bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mAdapterProperties.clear();
680d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
681d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String properties[] = (String [])getAdapterPropertiesNative();
682d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        // The String Array consists of key-value pairs.
683d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (properties == null) {
684d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            Log.e(TAG, "*Error*: GetAdapterProperties returned NULL");
685d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return;
686d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
687d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
6888bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh        for (int i = 0; i < properties.length; i++) {
6898bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            String name = properties[i];
690efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh            String newValue = null;
6918bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            int len;
6928bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            if (name == null) {
6938bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                Log.e(TAG, "Error:Adapter Property at index" + i + "is null");
6948bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                continue;
6958bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            }
6968bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            if (name.equals("Devices")) {
697efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                StringBuilder str = new StringBuilder();
6988bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                len = Integer.valueOf(properties[++i]);
6998bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                for (int j = 0; j < len; j++) {
700efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                    str.append(properties[++i]);
701efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                    str.append(",");
702efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                }
703efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                if (len > 0) {
704efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                    newValue = str.toString();
7058bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                }
7068bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            } else {
7078bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                newValue = properties[++i];
7088bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            }
709bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            mAdapterProperties.put(name, newValue);
710d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
711d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
712d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        // Add adapter object path property.
713d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String adapterPath = getAdapterPathNative();
714d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (adapterPath != null)
715bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            mAdapterProperties.put("ObjectPath", adapterPath + "/dev_");
7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
718d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ synchronized void setProperty(String name, String value) {
719bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mAdapterProperties.put(name, value);
7209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean setName(String name) {
7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
7259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (name == null) {
7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
728d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setPropertyString("Name", name);
7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
731d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    //TODO(): setPropertyString, setPropertyInteger, setPropertyBoolean
732d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    // Either have a single property function with Object as the parameter
733d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    // or have a function for each property and then obfuscate in the JNI layer.
734d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    // The following looks dirty.
735d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private boolean setPropertyString(String key, String value) {
7369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
737d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setAdapterPropertyStringNative(key, value);
7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
740d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private boolean setPropertyInteger(String key, int value) {
741d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
742d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setAdapterPropertyIntegerNative(key, value);
743d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
7449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
745d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private boolean setPropertyBoolean(String key, boolean value) {
746d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
747d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setAdapterPropertyBooleanNative(key, value ? 1 : 0);
7489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
750d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /**
751d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Set the discoverability window for the device.  A timeout of zero
752d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * makes the device permanently discoverable (if the device is
753d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * discoverable).  Setting the timeout to a nonzero value does not make
754d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * a device discoverable; you need to call setMode() to make the device
755d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * explicitly discoverable.
756d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     *
757d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * @param timeout_s The discoverable timeout in seconds.
758d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     */
759d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized boolean setDiscoverableTimeout(int timeout) {
7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
7619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
762d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setPropertyInteger("DiscoverableTimeout", timeout);
7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
76512835478ee687a493d1b5882e67b6725bd539c26Nick Pelly    public synchronized boolean setScanMode(int mode, int duration) {
76618b1e79a123b979d25bfa5d0b0ee5d0382dbd64bNick Pelly        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS,
76718b1e79a123b979d25bfa5d0b0ee5d0382dbd64bNick Pelly                                                "Need WRITE_SECURE_SETTINGS permission");
768de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        boolean pairable = false;
769de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        boolean discoverable = false;
77012835478ee687a493d1b5882e67b6725bd539c26Nick Pelly
771de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        switch (mode) {
772de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.SCAN_MODE_NONE:
77312835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            mHandler.removeMessages(MESSAGE_DISCOVERABLE_TIMEOUT);
774d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            pairable = false;
775d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            discoverable = false;
776de893f550301a60274e87aa8168225e7a7a42184Nick Pelly            break;
777de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
77812835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            mHandler.removeMessages(MESSAGE_DISCOVERABLE_TIMEOUT);
779d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            pairable = true;
780d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            discoverable = false;
781005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            break;
782de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
78312835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            mHandler.removeMessages(MESSAGE_DISCOVERABLE_TIMEOUT);
784d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            pairable = true;
785d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            discoverable = true;
78612835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            Message msg = mHandler.obtainMessage(MESSAGE_DISCOVERABLE_TIMEOUT);
78712835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            mHandler.sendMessageDelayed(msg, duration * 1000);
78812835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            if (DBG) Log.d(TAG, "BT Discoverable for " + duration + " seconds");
789005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            break;
790de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        default:
791de893f550301a60274e87aa8168225e7a7a42184Nick Pelly            Log.w(TAG, "Requested invalid scan mode " + mode);
792de893f550301a60274e87aa8168225e7a7a42184Nick Pelly            return false;
793d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
794d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        setPropertyBoolean("Pairable", pairable);
795d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        setPropertyBoolean("Discoverable", discoverable);
7969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
797d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return true;
7989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
800d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /*package*/ synchronized String getProperty (String name) {
801bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        if (!mAdapterProperties.isEmpty())
802bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            return mAdapterProperties.get(name);
803d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        getAllProperties();
804bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        return mAdapterProperties.get(name);
8059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
807d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized String getAddress() {
808d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
809d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return getProperty("Address");
8109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
812d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized String getName() {
8139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
814d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return getProperty("Name");
8159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
818d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Returns the user-friendly name of a remote device.  This value is
819d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * returned from our local cache, which is updated when onPropertyChange
820d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * event is received.
821d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Do not expect to retrieve the updated remote name immediately after
822d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * changing the name on the remote device.
8239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
824d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * @param address Bluetooth address of remote device.
825d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     *
826d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * @return The user-friendly name of the specified remote device.
8279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
828d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized String getRemoteName(String address) {
829d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
830005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
831d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return null;
832d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
83355929a958bf0e482c8e4d7df3dd75957f1e9d871Jaikumar Ganesh        return getRemoteDeviceProperty(address, "Name");
8349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
8379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Get the discoverability window for the device.  A timeout of zero
8389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * means that the device is permanently discoverable (if the device is
8399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * in the discoverable mode).
8409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
8419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The discoverability window of the device, in seconds.  A negative
8429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         value indicates an error.
8439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
8449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized int getDiscoverableTimeout() {
8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
846d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String timeout = getProperty("DiscoverableTimeout");
847d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (timeout != null)
848d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh           return Integer.valueOf(timeout);
849d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        else
850d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return -1;
8519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized int getScanMode() {
8549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
855d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (!isEnabled())
856de893f550301a60274e87aa8168225e7a7a42184Nick Pelly            return BluetoothAdapter.SCAN_MODE_NONE;
857d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
858d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        boolean pairable = getProperty("Pairable").equals("true");
859d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        boolean discoverable = getProperty("Discoverable").equals("true");
860d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return bluezStringToScanMode (pairable, discoverable);
8619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
863d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized boolean startDiscovery() {
8649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
8659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
866d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (!isEnabled()) {
867d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return false;
8689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
869d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return startDiscoveryNative();
8709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
872d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized boolean cancelDiscovery() {
8739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
8749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
875d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return stopDiscoveryNative();
876d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
877d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
878d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized boolean isDiscovering() {
879d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
880d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return mIsDiscovering;
881d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
882d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
883d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ void setIsDiscovering(boolean isDiscovering) {
884d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mIsDiscovering = isDiscovering;
8859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean createBond(String address) {
8889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
8899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
890005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        address = address.toUpperCase();
8949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8952092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        if (mBondState.getPendingOutgoingBonding() != null) {
8969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            log("Ignoring createBond(): another device is bonding");
8979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // a different device is currently bonding, fail
8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Check for bond state only if we are not performing auto
9029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // pairing exponential back-off attempts.
9039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mBondState.isAutoPairingAttemptsInProgress(address) &&
904005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly                mBondState.getBondState(address) != BluetoothDevice.BOND_NONE) {
9059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            log("Ignoring createBond(): this device is already bonding or bonded");
9069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
9079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
909d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (!createPairedDeviceNative(address, 60000 /* 1 minute */)) {
9109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
9119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9132092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        mBondState.setPendingOutgoingBonding(address);
9149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mBondState.setBondState(address, BluetoothDevice.BOND_BONDING);
9152092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
9169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
9179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean cancelBondProcess(String address) {
9209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
9219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
922005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
9239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
9249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        address = address.toUpperCase();
9269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mBondState.getBondState(address) != BluetoothDevice.BOND_BONDING) {
9279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
9289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
930005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        mBondState.setBondState(address, BluetoothDevice.BOND_NONE,
9319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
932d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        cancelDeviceCreationNative(address);
9339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
9349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean removeBond(String address) {
9379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
9389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
939005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
9409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
9419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
942d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return removeDeviceNative(getObjectPathFromAddress(address));
9439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized String[] listBonds() {
9469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
9479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mBondState.listInState(BluetoothDevice.BOND_BONDED);
9489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized int getBondState(String address) {
9519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
952005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
953b24e11baac589fe16426f2d243b460ab84991c7bNick Pelly            return BluetoothDevice.ERROR;
9549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mBondState.getBondState(address.toUpperCase());
9569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9589488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh    /*package*/ boolean isRemoteDeviceInCache(String address) {
959bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        return (mDeviceProperties.get(address) != null);
9609488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh    }
9619488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh
9629488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh    /*package*/ String[] getRemoteDeviceProperties(String address) {
9639488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh        String objectPath = getObjectPathFromAddress(address);
9649488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh        return (String [])getDevicePropertiesNative(objectPath);
9659488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh    }
9669488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh
967d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /*package*/ synchronized String getRemoteDeviceProperty(String address, String property) {
968bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        Map<String, String> properties = mDeviceProperties.get(address);
969d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (properties != null) {
970d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return properties.get(property);
971d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        } else {
972d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            // Query for remote device properties, again.
973d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            // We will need to reload the cache when we switch Bluetooth on / off
974d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            // or if we crash.
97510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            if (updateRemoteDevicePropertiesCache(address))
976d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                return getRemoteDeviceProperty(address, property);
9779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
978d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        Log.e(TAG, "getRemoteDeviceProperty: " + property + "not present:" + address);
979d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return null;
9809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
98210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh    /* package */ synchronized boolean updateRemoteDevicePropertiesCache(String address) {
98310eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        String[] propValues = getRemoteDeviceProperties(address);
98410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        if (propValues != null) {
98510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            addRemoteDeviceProperties(address, propValues);
98610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            return true;
98710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        }
98810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        return false;
98910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh    }
99010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
991d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ synchronized void addRemoteDeviceProperties(String address, String[] properties) {
992395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh        /*
993395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh         * We get a DeviceFound signal every time RSSI changes or name changes.
994395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh         * Don't create a new Map object every time */
995bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        Map<String, String> propertyValues = mDeviceProperties.get(address);
996efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh        if (propertyValues == null) {
997395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh            propertyValues = new HashMap<String, String>();
998395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh        }
999395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh
10008bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh        for (int i = 0; i < properties.length; i++) {
10018bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            String name = properties[i];
1002efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh            String newValue = null;
10038bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            int len;
10048bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            if (name == null) {
10058bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                Log.e(TAG, "Error: Remote Device Property at index" + i + "is null");
10068bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                continue;
10078bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            }
10088bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            if (name.equals("UUIDs") || name.equals("Nodes")) {
1009efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                StringBuilder str = new StringBuilder();
10108bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                len = Integer.valueOf(properties[++i]);
10118bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                for (int j = 0; j < len; j++) {
1012efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                    str.append(properties[++i]);
1013efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                    str.append(",");
1014efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                }
1015efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                if (len > 0) {
1016efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                    newValue = str.toString();
10178bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                }
1018d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            } else {
10198bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                newValue = properties[++i];
1020d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            }
1021efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh
10228bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            propertyValues.put(name, newValue);
10239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1024bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mDeviceProperties.put(address, propertyValues);
102510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
102610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        // We have added a new remote device or updated its properties.
102710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        // Also update the serviceChannel cache.
102810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        updateDeviceServiceChannelCache(address);
10299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1031d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ void removeRemoteDeviceProperties(String address) {
1032bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mDeviceProperties.remove(address);
10339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1035d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ synchronized void setRemoteDeviceProperty(String address, String name,
1036d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                                                              String value) {
1037bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        Map <String, String> propVal = mDeviceProperties.get(address);
1038d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (propVal != null) {
1039d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            propVal.put(name, value);
1040bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            mDeviceProperties.put(address, propVal);
1041d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        } else {
1042d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            Log.e(TAG, "setRemoteDeviceProperty for a device not in cache:" + address);
10439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1047efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * Sets the remote device trust state.
1048efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     *
1049efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * @return boolean to indicate operation success or fail
1050efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     */
1051efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    public synchronized boolean setTrust(String address, boolean value) {
1052005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1053e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly            mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1054e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly                    "Need BLUETOOTH_ADMIN permission");
1055efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            return false;
1056efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        }
1057efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue
1058efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        return setDevicePropertyBooleanNative(getObjectPathFromAddress(address), "Trusted",
1059efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue                value ? 1 : 0);
1060efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    }
1061efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue
1062efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    /**
1063efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * Gets the remote device trust state as boolean.
1064efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * Note: this value may be
1065efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * retrieved from cache if we retrieved the data before *
1066efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     *
1067efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * @return boolean to indicate trust or untrust state
1068efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     */
1069efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    public synchronized boolean getTrustState(String address) {
1070005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1071efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1072efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            return false;
1073efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        }
1074efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue
1075efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        String val = getRemoteDeviceProperty(address, "Trusted");
1076efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        if (val == null) {
1077efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            return false;
1078efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        } else {
1079efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            return val.equals("true") ? true : false;
1080efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        }
1081efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    }
1082efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue
1083efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    /**
1084d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Gets the remote major, minor classes encoded as a 32-bit
10859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * integer.
10869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
10879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Note: this value is retrieved from cache, because we get it during
10889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *       remote-device discovery.
10899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
10909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return 32-bit integer encoding the remote major, minor, and service
10919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         classes.
10929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
10939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized int getRemoteClass(String address) {
1094005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1095ea600ccfb7568f60377c4abc85f56c80af7fdbfcNick Pelly            mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1096ea600ccfb7568f60377c4abc85f56c80af7fdbfcNick Pelly            return BluetoothClass.ERROR;
10979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1098d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String val = getRemoteDeviceProperty(address, "Class");
1099d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (val == null)
1100d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return BluetoothClass.ERROR;
1101d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        else {
1102d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return Integer.valueOf(val);
1103d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
11049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1105d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
11069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1108dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh     * Gets the UUIDs supported by the remote device
11099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1110dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh     * @return array of 128bit ParcelUuids
11119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1112dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh    public synchronized ParcelUuid[] getRemoteUuids(String address) {
11139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1114005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
11159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return null;
11169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11171caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        return getUuidFromCache(address);
11181caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    }
11191caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
11201caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    private ParcelUuid[] getUuidFromCache(String address) {
1121d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String value = getRemoteDeviceProperty(address, "UUIDs");
1122dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        if (value == null) return null;
1123dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh
1124dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        String[] uuidStrings = null;
1125d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        // The UUIDs are stored as a "," separated string.
1126dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        uuidStrings = value.split(",");
1127dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        ParcelUuid[] uuids = new ParcelUuid[uuidStrings.length];
1128dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh
1129dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        for (int i = 0; i < uuidStrings.length; i++) {
1130dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh            uuids[i] = ParcelUuid.fromString(uuidStrings[i]);
1131dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        }
1132d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return uuids;
11339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
113516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    /**
113616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * Connect and fetch new UUID's using SDP.
113716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * The UUID's found are broadcast as intents.
113816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * Optionally takes a uuid and callback to fetch the RFCOMM channel for the
113916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * a given uuid.
114016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * TODO: Don't wait UUID_INTENT_DELAY to broadcast UUID intents on success
114116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * TODO: Don't wait UUID_INTENT_DELAY to handle the failure case for
114216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * callback and broadcast intents.
114316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     */
114416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    public synchronized boolean fetchRemoteUuids(String address, ParcelUuid uuid,
114516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            IBluetoothCallback callback) {
11461caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
11471caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
11481caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            return false;
11491caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        }
11501caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
115116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        RemoteService service = new RemoteService(address, uuid);
115216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        if (uuid != null && mUuidCallbackTracker.get(service) != null) {
115316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            // An SDP query for this address & uuid is already in progress
115416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            // Do not add this callback for the uuid
115516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            return false;
115616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
115716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
11581caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        if (mUuidIntentTracker.contains(address)) {
11591caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            // An SDP query for this address is already in progress
116016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            // Add this uuid onto the in-progress SDP query
116116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (uuid != null) {
116216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                mUuidCallbackTracker.put(new RemoteService(address, uuid), callback);
116316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
11641caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            return true;
11651caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        }
11661caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
11671caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        boolean ret;
11681caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        if (getBondState(address) == BluetoothDevice.BOND_BONDED) {
11691caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            String path = getObjectPathFromAddress(address);
11701caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            if (path == null) return false;
11711caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
11721caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            // Use an empty string for the UUID pattern
11731caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            ret = discoverServicesNative(path, "");
11741caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        } else {
11751caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            ret = createDeviceNative(address);
11761caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        }
11771caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
11781caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        mUuidIntentTracker.add(address);
117916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        if (uuid != null) {
118016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            mUuidCallbackTracker.put(new RemoteService(address, uuid), callback);
118116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
11821caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
11831caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        Message message = mHandler.obtainMessage(MESSAGE_UUID_INTENT);
11841caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        message.obj = address;
11851caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        mHandler.sendMessageDelayed(message, UUID_INTENT_DELAY);
11861caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        return ret;
11871caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    }
11881caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
11899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1190d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Gets the rfcomm channel associated with the UUID.
119116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * Pulls records from the cache only.
11929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1193d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * @param address Address of the remote device
1194dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh     * @param uuid ParcelUuid of the service attribute
11959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1196d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * @return rfcomm channel associated with the service attribute
119710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh     *         -1 on error
11989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1199dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh    public int getRemoteServiceChannel(String address, ParcelUuid uuid) {
12009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1201005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1202b24e11baac589fe16426f2d243b460ab84991c7bNick Pelly            return BluetoothDevice.ERROR;
12039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
120410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        // Check if we are recovering from a crash.
120510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        if (mDeviceProperties.isEmpty()) {
120610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            if (!updateRemoteDevicePropertiesCache(address))
120710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh                return -1;
120810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        }
120910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
121010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        Map<ParcelUuid, Integer> value = mDeviceServiceChannelCache.get(address);
121110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        if (value != null && value.containsKey(uuid))
121210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            return value.get(uuid);
121310eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        return -1;
12149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean setPin(String address, byte[] pin) {
12179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
12189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
12199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (pin == null || pin.length <= 0 || pin.length > 16 ||
1220005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            !BluetoothAdapter.checkBluetoothAddress(address)) {
12219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
12229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        address = address.toUpperCase();
12249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
12259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (data == null) {
12269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.w(TAG, "setPin(" + address + ") called but no native data available, " +
12279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                  "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
12289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                  " or by bluez.\n");
12299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
12309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // bluez API wants pin as a string
12329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String pinString;
12339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
12349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pinString = new String(pin, "UTF8");
12359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (UnsupportedEncodingException uee) {
12369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.e(TAG, "UTF8 not supported?!?");
12379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
12389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return setPinNative(address, pinString, data.intValue());
12409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1242b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    public synchronized boolean setPasskey(String address, int passkey) {
1243b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1244b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                                                "Need BLUETOOTH_ADMIN permission");
1245005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (passkey < 0 || passkey > 999999 || !BluetoothAdapter.checkBluetoothAddress(address)) {
1246b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            return false;
1247b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        }
1248b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        address = address.toUpperCase();
1249b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
1250b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        if (data == null) {
1251b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            Log.w(TAG, "setPasskey(" + address + ") called but no native data available, " +
1252b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                  "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
1253b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                  " or by bluez.\n");
1254b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            return false;
1255b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        }
1256b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        return setPasskeyNative(address, passkey, data.intValue());
1257b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    }
1258b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh
1259b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    public synchronized boolean setPairingConfirmation(String address, boolean confirm) {
1260b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1261b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                                                "Need BLUETOOTH_ADMIN permission");
1262b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        address = address.toUpperCase();
1263b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
1264b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        if (data == null) {
1265b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            Log.w(TAG, "setPasskey(" + address + ") called but no native data available, " +
1266b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                  "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
1267b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                  " or by bluez.\n");
1268b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            return false;
1269b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        }
1270b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        return setPairingConfirmationNative(address, confirm, data.intValue());
1271b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    }
1272b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh
1273b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    public synchronized boolean cancelPairingUserInput(String address) {
12749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
12759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
1276005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
12779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
12789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1279005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        mBondState.setBondState(address, BluetoothDevice.BOND_NONE,
1280397d8f4f4829a45f4fe7a672cc395466bbc0f442Jaikumar Ganesh                BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
12819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        address = address.toUpperCase();
12829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
12839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (data == null) {
1284b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            Log.w(TAG, "cancelUserInputNative(" + address + ") called but no native data " +
1285b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                "available, ignoring. Maybe the PasskeyAgent Request was already cancelled " +
1286b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                "by the remote or by bluez.\n");
12879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
12889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1289b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        return cancelPairingUserInputNative(address, data.intValue());
12909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
129210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh    public void updateDeviceServiceChannelCache(String address) {
129310eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        ParcelUuid[] deviceUuids = getRemoteUuids(address);
129410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        // We are storing the rfcomm channel numbers only for the uuids
129510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        // we are interested in.
129610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        int channel;
129716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        if (DBG) log("updateDeviceServiceChannelCache(" + address + ")");
129816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
129916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        ArrayList<ParcelUuid> applicationUuids = new ArrayList();
130016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
130116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        synchronized (this) {
130216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            for (RemoteService service : mUuidCallbackTracker.keySet()) {
130316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (service.address.equals(address)) {
130416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    applicationUuids.add(service.uuid);
130516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                }
130616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
130716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
130810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
130910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        Map <ParcelUuid, Integer> value = new HashMap<ParcelUuid, Integer>();
131016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
131116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        // Retrieve RFCOMM channel for default uuids
131216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        for (ParcelUuid uuid : RFCOMM_UUIDS) {
131310eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            if (BluetoothUuid.isUuidPresent(deviceUuids, uuid)) {
131416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                channel = getDeviceServiceChannelNative(getObjectPathFromAddress(address),
131516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        uuid.toString(), 0x0004);
131616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (DBG) log("\tuuid(system): " + uuid + " " + channel);
131710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh                value.put(uuid, channel);
131810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            }
131910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        }
132016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        // Retrieve RFCOMM channel for application requested uuids
132116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        for (ParcelUuid uuid : applicationUuids) {
132216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (BluetoothUuid.isUuidPresent(deviceUuids, uuid)) {
132316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                channel = getDeviceServiceChannelNative(getObjectPathFromAddress(address),
132416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        uuid.toString(), 0x0004);
132516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (DBG) log("\tuuid(application): " + uuid + " " + channel);
132616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                value.put(uuid, channel);
132716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
132816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
132916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
133016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        synchronized (this) {
133116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            // Make application callbacks
133216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            for (Iterator<RemoteService> iter = mUuidCallbackTracker.keySet().iterator();
133316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    iter.hasNext();) {
133416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                RemoteService service = iter.next();
133516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (service.address.equals(address)) {
133616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    channel = -1;
133716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    if (value.get(service.uuid) != null) {
133816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        channel = value.get(service.uuid);
133916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    }
134016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    if (channel != -1) {
134116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        if (DBG) log("Making callback for " + service.uuid + " with result " +
134216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                                channel);
134316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        IBluetoothCallback callback = mUuidCallbackTracker.get(service);
134416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        if (callback != null) {
134516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                            try {
134616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                                callback.onRfcommChannelFound(channel);
134716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                            } catch (RemoteException e) {Log.e(TAG, "", e);}
134816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        }
134916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
135016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        iter.remove();
135116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    }
135216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                }
135316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
135416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
135516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            // Update cache
135616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            mDeviceServiceChannelCache.put(address, value);
135716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
135810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh    }
135910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
136024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    /**
136124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     * b is a handle to a Binder instance, so that this service can be notified
136224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     * for Applications that terminate unexpectedly, to clean there service
136324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     * records
136424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     */
136524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    public synchronized int addRfcommServiceRecord(String serviceName, ParcelUuid uuid,
136624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            int channel, IBinder b) {
136724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
136824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                                                "Need BLUETOOTH permission");
136924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (serviceName == null || uuid == null || channel < 1 ||
137024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                channel > BluetoothSocket.MAX_RFCOMM_CHANNEL) {
137124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            return -1;
137224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
137324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (BluetoothUuid.isUuidPresent(BluetoothUuid.RESERVED_UUIDS, uuid)) {
137424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            Log.w(TAG, "Attempted to register a reserved UUID: " + uuid);
137524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            return -1;
137624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
137724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        int handle = addRfcommServiceRecordNative(serviceName,
137824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                uuid.getUuid().getMostSignificantBits(), uuid.getUuid().getLeastSignificantBits(),
137924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                (short)channel);
138024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (DBG) log("new handle " + Integer.toHexString(handle));
138124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (handle == -1) {
138224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            return -1;
138324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
138424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
138524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        int pid = Binder.getCallingPid();
138624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        mServiceRecordToPid.put(new Integer(handle), new Integer(pid));
138724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        try {
138824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            b.linkToDeath(new Reaper(handle, pid), 0);
138924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        } catch (RemoteException e) {}
139024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        return handle;
139124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    }
139224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
139324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    public void removeServiceRecord(int handle) {
139424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
139524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                                                "Need BLUETOOTH permission");
139624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        checkAndRemoveRecord(handle, Binder.getCallingPid());
139724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    }
139824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
139924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private synchronized void checkAndRemoveRecord(int handle, int pid) {
140024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        Integer handleInt = new Integer(handle);
140124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        Integer owner = mServiceRecordToPid.get(handleInt);
140224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (owner != null && pid == owner.intValue()) {
140324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            if (DBG) log("Removing service record " + Integer.toHexString(handle) + " for pid " +
140424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                    pid);
140524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            mServiceRecordToPid.remove(handleInt);
140624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            removeServiceRecordNative(handle);
140724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
140824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    }
140924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
141024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private class Reaper implements IBinder.DeathRecipient {
141124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        int pid;
141224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        int handle;
141324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        Reaper(int handle, int pid) {
141424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            this.pid = pid;
141524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            this.handle = handle;
141624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
141724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        public void binderDied() {
141824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            synchronized (BluetoothService.this) {
141924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                if (DBG) log("Tracked app " + pid + " died");
142024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                checkAndRemoveRecord(handle, pid);
142124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            }
142224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
142324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    }
142424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
14259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
14269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
14279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onReceive(Context context, Intent intent) {
14289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String action = intent.getAction();
14299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
14309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ContentResolver resolver = context.getContentResolver();
14319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Query the airplane mode from Settings.System just to make sure that
14329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // some random app is not sending this intent and disabling bluetooth
14339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                boolean enabled = !isAirplaneModeOn();
14349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // If bluetooth is currently expected to be on, then enable or disable bluetooth
14359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (Settings.Secure.getInt(resolver, Settings.Secure.BLUETOOTH_ON, 0) > 0) {
14369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (enabled) {
1437105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                        enable(false);
14389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } else {
14399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        disable(false);
14409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
14419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
14429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
14439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
14449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
14459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void registerForAirplaneMode() {
14479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String airplaneModeRadios = Settings.System.getString(mContext.getContentResolver(),
14489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Settings.System.AIRPLANE_MODE_RADIOS);
14499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mIsAirplaneSensitive = airplaneModeRadios == null
14509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ? true : airplaneModeRadios.contains(Settings.System.RADIO_BLUETOOTH);
14519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mIsAirplaneSensitive) {
14529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mIntentFilter = new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
14539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mContext.registerReceiver(mReceiver, mIntentFilter);
14549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
14559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* Returns true if airplane mode is currently on */
14589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final boolean isAirplaneModeOn() {
14599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return Settings.System.getInt(mContext.getContentResolver(),
14609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Settings.System.AIRPLANE_MODE_ON, 0) == 1;
14619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14631caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    /* Broadcast the Uuid intent */
14641caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    /*package*/ synchronized void sendUuidIntent(String address) {
14656179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh        ParcelUuid[] uuid = getUuidFromCache(address);
14666179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh        Intent intent = new Intent(BluetoothDevice.ACTION_UUID);
14672d3b98d868cda30535505b2a2fba47aa1c9c052bJaikumar Ganesh        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
14686179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh        intent.putExtra(BluetoothDevice.EXTRA_UUID, uuid);
14696179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh        mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
14701caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
14716179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh        if (mUuidIntentTracker.contains(address))
14721caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            mUuidIntentTracker.remove(address);
147316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
147416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    }
147516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
147616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    /*package*/ synchronized void makeServiceChannelCallbacks(String address) {
147716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        for (Iterator<RemoteService> iter = mUuidCallbackTracker.keySet().iterator();
147816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                iter.hasNext();) {
147916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            RemoteService service = iter.next();
148016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (service.address.equals(address)) {
148116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (DBG) log("Cleaning up failed UUID channel lookup: " + service.address +
148216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        " " + service.uuid);
148316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                IBluetoothCallback callback = mUuidCallbackTracker.get(service);
148416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (callback != null) {
148516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    try {
148616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        callback.onRfcommChannelFound(-1);
148716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    } catch (RemoteException e) {Log.e(TAG, "", e);}
148816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                }
148916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
149016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                iter.remove();
149116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
149216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
14931caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    }
14941caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
14959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
14969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1497105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        switch(mBluetoothState) {
1498de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_OFF:
149924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            pw.println("Bluetooth OFF\n");
1500105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return;
1501de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_TURNING_ON:
150224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            pw.println("Bluetooth TURNING ON\n");
1503105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return;
1504de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_TURNING_OFF:
150524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            pw.println("Bluetooth TURNING OFF\n");
1506105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return;
1507de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_ON:
150824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            pw.println("Bluetooth ON\n");
1509105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
1510105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
151124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("mIsAirplaneSensitive = " + mIsAirplaneSensitive);
151224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
151324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("Local address = " + getAddress());
151424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("Local name = " + getName());
151524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("isDiscovering() = " + isDiscovering());
1516105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
1517105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        BluetoothHeadset headset = new BluetoothHeadset(mContext, null);
1518105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
1519105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        pw.println("\n--Known devices--");
1520bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        for (String address : mDeviceProperties.keySet()) {
15211eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly            int bondState = mBondState.getBondState(address);
1522105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            pw.printf("%s %10s (%d) %s\n", address,
15231eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly                       toBondStateString(bondState),
1524105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                       mBondState.getAttempt(address),
1525105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                       getRemoteName(address));
152624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
152724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            Map<ParcelUuid, Integer> uuidChannels = mDeviceServiceChannelCache.get(address);
152824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            if (uuidChannels == null) {
152924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                pw.println("\tuuids = null");
153024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            } else {
153124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                for (ParcelUuid uuid : uuidChannels.keySet()) {
153224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                    Integer channel = uuidChannels.get(uuid);
153324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                    if (channel == null) {
153424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                        pw.println("\t" + uuid);
153524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                    } else {
153624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                        pw.println("\t" + uuid + " RFCOMM channel = " + channel);
15371eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly                    }
15381eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly                }
15391eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly            }
154016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            for (RemoteService service : mUuidCallbackTracker.keySet()) {
154116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (service.address.equals(address)) {
154216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    pw.println("\tPENDING CALLBACK: " + service.uuid);
154316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                }
154416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
1545105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
1546105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
1547d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String value = getProperty("Devices");
15481eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly        String[] devicesObjectPath = null;
1549d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (value != null) {
1550d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            devicesObjectPath = value.split(",");
1551d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
1552105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        pw.println("\n--ACL connected devices--");
155324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (devicesObjectPath != null) {
155424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            for (String device : devicesObjectPath) {
155524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                pw.println(getAddressFromObjectPath(device));
155624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            }
1557105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
1558105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
1559105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Rather not do this from here, but no-where else and I need this
1560105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // dump
1561105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        pw.println("\n--Headset Service--");
1562105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        switch (headset.getState()) {
1563105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        case BluetoothHeadset.STATE_DISCONNECTED:
1564105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            pw.println("getState() = STATE_DISCONNECTED");
1565105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            break;
1566105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        case BluetoothHeadset.STATE_CONNECTING:
1567105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            pw.println("getState() = STATE_CONNECTING");
1568105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            break;
1569105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        case BluetoothHeadset.STATE_CONNECTED:
1570105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            pw.println("getState() = STATE_CONNECTED");
1571105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            break;
1572105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        case BluetoothHeadset.STATE_ERROR:
1573105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            pw.println("getState() = STATE_ERROR");
1574105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            break;
1575105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
15766c901db72dbaf57d8fdf26adae6721de14ecae22Nick Pelly
157724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("\ngetCurrentHeadset() = " + headset.getCurrentHeadset());
157824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("getBatteryUsageHint() = " + headset.getBatteryUsageHint());
1579105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        headset.close();
158024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("\n--Application Service Records--");
158124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        for (Integer handle : mServiceRecordToPid.keySet()) {
158224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            Integer pid = mServiceRecordToPid.get(handle);
158324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            pw.println("\tpid " + pid + " handle " + Integer.toHexString(handle));
158424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
15859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
15869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1587d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ static int bluezStringToScanMode(boolean pairable, boolean discoverable) {
1588d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (pairable && discoverable)
1589bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            return BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE;
1590d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        else if (pairable && !discoverable)
1591bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            return BluetoothAdapter.SCAN_MODE_CONNECTABLE;
1592d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        else
1593bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            return BluetoothAdapter.SCAN_MODE_NONE;
15949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
15959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* package */ static String scanModeToBluezString(int mode) {
15979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        switch (mode) {
1598bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        case BluetoothAdapter.SCAN_MODE_NONE:
15999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "off";
1600bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
16019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "connectable";
1602bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
16039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "discoverable";
16049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
16059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return null;
16069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
16079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1608d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /*package*/ String getAddressFromObjectPath(String objectPath) {
1609d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String adapterObjectPath = getProperty("ObjectPath");
1610d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (adapterObjectPath == null || objectPath == null) {
1611d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            Log.e(TAG, "getAddressFromObjectPath: AdpaterObjectPath:" + adapterObjectPath +
1612d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                    "  or deviceObjectPath:" + objectPath + " is null");
1613d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return null;
1614d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
1615d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (!objectPath.startsWith(adapterObjectPath)) {
1616d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            Log.e(TAG, "getAddressFromObjectPath: AdpaterObjectPath:" + adapterObjectPath +
1617d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                    "  is not a prefix of deviceObjectPath:" + objectPath +
1618d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                    "bluetoothd crashed ?");
1619d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return null;
1620d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
1621d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String address = objectPath.substring(adapterObjectPath.length());
1622d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (address != null) return address.replace('_', ':');
1623d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1624d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        Log.e(TAG, "getAddressFromObjectPath: Address being returned is null");
1625d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return null;
1626d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
1627d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1628d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /*package*/ String getObjectPathFromAddress(String address) {
1629d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String path = getProperty("ObjectPath");
1630d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (path == null) {
1631d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            Log.e(TAG, "Error: Object Path is null");
1632d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return null;
1633d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
1634d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        path = path + address.replace(":", "_");
1635d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return path;
1636d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
1637d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
16389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static void log(String msg) {
16399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Log.d(TAG, msg);
16409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1641d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1642d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native static void classInitNative();
1643d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native void initializeNativeDataNative();
1644d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setupNativeDataNative();
1645d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean tearDownNativeDataNative();
1646d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native void cleanupNativeDataNative();
1647d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native String getAdapterPathNative();
1648d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1649d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native int isEnabledNative();
1650d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native int enableNative();
1651d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native int disableNative();
1652d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1653d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native Object[] getAdapterPropertiesNative();
1654d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native Object[] getDevicePropertiesNative(String objectPath);
1655d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setAdapterPropertyStringNative(String key, String value);
1656d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setAdapterPropertyIntegerNative(String key, int value);
1657d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setAdapterPropertyBooleanNative(String key, int value);
1658d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1659d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean startDiscoveryNative();
1660d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean stopDiscoveryNative();
1661d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1662d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean createPairedDeviceNative(String address, int timeout_ms);
1663d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean cancelDeviceCreationNative(String address);
1664d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean removeDeviceNative(String objectPath);
1665d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native int getDeviceServiceChannelNative(String objectPath, String uuid,
1666d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            int attributeId);
1667d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1668b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    private native boolean cancelPairingUserInputNative(String address, int nativeData);
1669d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setPinNative(String address, String pin, int nativeData);
1670b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    private native boolean setPasskeyNative(String address, int passkey, int nativeData);
1671b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    private native boolean setPairingConfirmationNative(String address, boolean confirm,
1672b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            int nativeData);
167324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private native boolean setDevicePropertyBooleanNative(String objectPath, String key,
167424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            int value);
16751caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    private native boolean createDeviceNative(String address);
167616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    /*package*/ native boolean discoverServicesNative(String objectPath, String pattern);
167710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
167824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private native int addRfcommServiceRecordNative(String name, long uuidMsb, long uuidLsb,
167924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            short channel);
168024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private native boolean removeServiceRecordNative(int handle);
16819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1682