BluetoothService.java revision 05a1863cebcc8e318283f3f4a49ba69d83b62866
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
27545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganeshimport android.bluetooth.BluetoothA2dp;
28bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pellyimport android.bluetooth.BluetoothAdapter;
29dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganeshimport android.bluetooth.BluetoothClass;
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.bluetooth.BluetoothDevice;
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.bluetooth.BluetoothHeadset;
32f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganeshimport android.bluetooth.BluetoothDeviceProfileState;
33f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganeshimport android.bluetooth.BluetoothProfileState;
34545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganeshimport android.bluetooth.BluetoothInputDevice;
3524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pellyimport android.bluetooth.BluetoothSocket;
3610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganeshimport android.bluetooth.BluetoothUuid;
37bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pellyimport android.bluetooth.IBluetooth;
3816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pellyimport android.bluetooth.IBluetoothCallback;
39545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganeshimport android.bluetooth.IBluetoothHeadset;
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.BroadcastReceiver;
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ContentResolver;
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Intent;
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.IntentFilter;
456e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganeshimport android.content.SharedPreferences;
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Binder;
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Handler;
483fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport android.os.IBinder;
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Message;
503fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport android.os.ParcelUuid;
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.RemoteException;
52105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Projectimport android.os.ServiceManager;
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemService;
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.Settings;
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log;
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
57d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganeshimport com.android.internal.app.IBatteryStats;
58d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
593fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.BufferedInputStream;
60c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganeshimport java.io.BufferedReader;
613fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.BufferedWriter;
62c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganeshimport java.io.DataInputStream;
63c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganeshimport java.io.File;
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileDescriptor;
653fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.FileInputStream;
663fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.FileNotFoundException;
67c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganeshimport java.io.FileOutputStream;
683fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.FileWriter;
693fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.IOException;
70c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganeshimport java.io.InputStreamReader;
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.PrintWriter;
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.UnsupportedEncodingException;
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList;
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Arrays;
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.HashMap;
76545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganeshimport java.util.HashSet;
7716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pellyimport java.util.Iterator;
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Map;
79545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganeshimport java.util.Set;
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
81bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pellypublic class BluetoothService extends IBluetooth.Stub {
82bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    private static final String TAG = "BluetoothService";
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final boolean DBG = true;
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mNativeData;
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private BluetoothEventLoop mEventLoop;
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mIsAirplaneSensitive;
8844303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey    private boolean mIsAirplaneToggleable;
89105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private int mBluetoothState;
90997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly    private boolean mRestart = false;  // need to call enable() after disable()
91bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    private boolean mIsDiscovering;
92997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly
93bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    private BluetoothAdapter mAdapter;  // constant after init()
94997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly    private final BondState mBondState = new BondState();  // local cache of bondings
95105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private final IBatteryStats mBatteryStats;
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final Context mContext;
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1013fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    private static final String DOCK_ADDRESS_PATH = "/sys/class/switch/dock/bt_addr";
1023fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    private static final String DOCK_PIN_PATH = "/sys/class/switch/dock/bt_pin";
1033fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
1046e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh    private static final String SHARED_PREFERENCE_DOCK_ADDRESS = "dock_bluetooth_address";
1056e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh    private static final String SHARED_PREFERENCES_NAME = "bluetooth_service_settings";
1066e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh
107105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private static final int MESSAGE_REGISTER_SDP_RECORDS = 1;
108105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private static final int MESSAGE_FINISH_DISABLE = 2;
1091caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    private static final int MESSAGE_UUID_INTENT = 3;
11012835478ee687a493d1b5882e67b6725bd539c26Nick Pelly    private static final int MESSAGE_DISCOVERABLE_TIMEOUT = 4;
1111caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
1121caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    // The timeout used to sent the UUIDs Intent
1131caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    // This timeout should be greater than the page timeout
1141caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    private static final int UUID_INTENT_DELAY = 6000;
115105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
11616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    /** Always retrieve RFCOMM channel for these SDP UUIDs */
11716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private static final ParcelUuid[] RFCOMM_UUIDS = {
11816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            BluetoothUuid.Handsfree,
11916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            BluetoothUuid.HSP,
12016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            BluetoothUuid.ObexObjectPush };
12116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
1229b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    // TODO(): Optimize all these string handling
123bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    private final Map<String, String> mAdapterProperties;
12416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private final HashMap<String, Map<String, String>> mDeviceProperties;
125d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
12616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private final HashMap<String, Map<ParcelUuid, Integer>> mDeviceServiceChannelCache;
12716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private final ArrayList<String> mUuidIntentTracker;
12816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private final HashMap<RemoteService, IBluetoothCallback> mUuidCallbackTracker;
1291caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
13024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private final HashMap<Integer, Integer> mServiceRecordToPid;
13124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
132f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh    private final HashMap<String, BluetoothDeviceProfileState> mDeviceProfileState;
133f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh    private final BluetoothProfileState mA2dpProfileState;
134f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh    private final BluetoothProfileState mHfpProfileState;
135de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh    private final BluetoothProfileState mHidProfileState;
1369b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
1379b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    private BluetoothA2dpService mA2dpService;
138545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh    private final HashMap<BluetoothDevice, Integer> mInputDevices;
139545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh
1403fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    private static String mDockAddress;
1413fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    private String mDockPin;
1423fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
14316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private static class RemoteService {
14416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        public String address;
14516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        public ParcelUuid uuid;
14616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        public RemoteService(String address, ParcelUuid uuid) {
14716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            this.address = address;
14816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            this.uuid = uuid;
14916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
15016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        @Override
15116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        public boolean equals(Object o) {
15216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (o instanceof RemoteService) {
15316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                RemoteService service = (RemoteService)o;
15416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                return address.equals(service.address) && uuid.equals(service.uuid);
15516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
15616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            return false;
15716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
1585f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root
1595f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root        @Override
1605f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root        public int hashCode() {
1615f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root            int hash = 1;
1625f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root            hash = hash * 31 + (address == null ? 0 : address.hashCode());
1635f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root            hash = hash * 31 + (uuid == null ? 0 : uuid.hashCode());
1645f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root            return hash;
1655f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root        }
16616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    }
16716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static {
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        classInitNative();
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
172bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    public BluetoothService(Context context) {
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext = context;
174105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
175105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Need to do this in place of:
176105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // mBatteryStats = BatteryStatsService.getService();
177105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Since we can not import BatteryStatsService from here. This class really needs to be
178105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // moved to java/services/com/android/server/
179105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo"));
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        initializeNativeDataNative();
182ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project
183ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project        if (isEnabledNative() == 1) {
184ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project            Log.w(TAG, "Bluetooth daemons already running - runtime restart? ");
185ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project            disableNative();
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
187ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project
188de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        mBluetoothState = BluetoothAdapter.STATE_OFF;
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mIsDiscovering = false;
190bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mAdapterProperties = new HashMap<String, String>();
191bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mDeviceProperties = new HashMap<String, Map<String,String>>();
19210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
19310eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        mDeviceServiceChannelCache = new HashMap<String, Map<ParcelUuid, Integer>>();
1941caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        mUuidIntentTracker = new ArrayList<String>();
19516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        mUuidCallbackTracker = new HashMap<RemoteService, IBluetoothCallback>();
19624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        mServiceRecordToPid = new HashMap<Integer, Integer>();
197f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        mDeviceProfileState = new HashMap<String, BluetoothDeviceProfileState>();
198f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        mA2dpProfileState = new BluetoothProfileState(mContext, BluetoothProfileState.A2DP);
199f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        mHfpProfileState = new BluetoothProfileState(mContext, BluetoothProfileState.HFP);
200de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh        mHidProfileState = new BluetoothProfileState(mContext, BluetoothProfileState.HID);
201f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh
202f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        mHfpProfileState.start();
203f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        mA2dpProfileState.start();
204de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh        mHidProfileState.start();
2053fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
2063fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        IntentFilter filter = new IntentFilter();
2076e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh        registerForAirplaneMode(filter);
2086e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh
2093fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        filter.addAction(Intent.ACTION_DOCK_EVENT);
2106e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh        mContext.registerReceiver(mReceiver, filter);
211545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        mInputDevices = new HashMap<BluetoothDevice, Integer>();
2123fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    }
2133fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
2149b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public static synchronized String readDockBluetoothAddress() {
2153fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        if (mDockAddress != null) return mDockAddress;
2163fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
2173fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        BufferedInputStream file = null;
2183fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        String dockAddress;
2193fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        try {
2203fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            file = new BufferedInputStream(new FileInputStream(DOCK_ADDRESS_PATH));
2213fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            byte[] address = new byte[17];
2223fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            file.read(address);
2233fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            dockAddress = new String(address);
2243fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            dockAddress = dockAddress.toUpperCase();
2253fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            if (BluetoothAdapter.checkBluetoothAddress(dockAddress)) {
2263fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                mDockAddress = dockAddress;
2273fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                return mDockAddress;
2283fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            } else {
2293fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                log("CheckBluetoothAddress failed for car dock address:" + dockAddress);
2303fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            }
2313fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        } catch (FileNotFoundException e) {
2323fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            log("FileNotFoundException while trying to read dock address");
2333fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        } catch (IOException e) {
2343fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            log("IOException while trying to read dock address");
2353fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        } finally {
2363fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            if (file != null) {
2373fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                try {
2383fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                    file.close();
2393fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                } catch (IOException e) {
2403fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                    // Ignore
2413fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                }
2423fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            }
2433fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        }
2443fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        mDockAddress = null;
2453fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        return null;
2463fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    }
2473fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
2483fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    private synchronized boolean writeDockPin() {
2493fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        BufferedWriter out = null;
2503fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        try {
2513fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            out = new BufferedWriter(new FileWriter(DOCK_PIN_PATH));
2523fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
2533fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            // Generate a random 4 digit pin between 0000 and 9999
2543fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            // This is not truly random but good enough for our purposes.
2553fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            int pin = (int) Math.floor(Math.random() * 10000);
2563fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
2573fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            mDockPin = String.format("%04d", pin);
2583fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            out.write(mDockPin);
2593fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            return true;
2603fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        } catch (FileNotFoundException e) {
2613fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            log("FileNotFoundException while trying to write dock pairing pin");
2623fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        } catch (IOException e) {
2633fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            log("IOException while while trying to write dock pairing pin");
2643fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        } finally {
2653fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            if (out != null) {
2663fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                try {
2673fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                    out.close();
2683fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                } catch (IOException e) {
2693fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                    // Ignore
2703fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                }
2713fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            }
2723fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        }
2733fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        mDockPin = null;
2743fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        return false;
2753fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    }
2763fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
2773fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    /*package*/ synchronized String getDockPin() {
2783fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        return mDockPin;
279bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    }
280bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly
281bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    public synchronized void initAfterRegistration() {
282f242b7b931898856bcbcb7ec36cacf43098ba544Nick Pelly        mAdapter = BluetoothAdapter.getDefaultAdapter();
283bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mEventLoop = new BluetoothEventLoop(mContext, mAdapter, this);
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void finalize() throws Throwable {
2886e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh        mContext.unregisterReceiver(mReceiver);
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            cleanupNativeDataNative();
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super.finalize();
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean isEnabled() {
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
2988c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        return isEnabledInternal();
2998c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh    }
3008c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
3018c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh    private boolean isEnabledInternal() {
302de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        return mBluetoothState == BluetoothAdapter.STATE_ON;
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
305105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    public int getBluetoothState() {
306105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
307105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        return mBluetoothState;
308105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    }
309105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
310105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Bring down bluetooth and disable BT in settings. Returns true on success.
3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean disable() {
3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return disable(true);
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Bring down bluetooth. Returns true on success.
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
321e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly     * @param saveSetting If true, persist the new setting
3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean disable(boolean saveSetting) {
324e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission");
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
326105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        switch (mBluetoothState) {
327de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_OFF:
328105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return true;
329de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_ON:
330105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            break;
331105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        default:
332105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return false;
333105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mEnableThread != null && mEnableThread.isAlive()) {
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
337de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        setBluetoothState(BluetoothAdapter.STATE_TURNING_OFF);
338bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly        mHandler.removeMessages(MESSAGE_REGISTER_SDP_RECORDS);
339105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
340105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Allow 3 seconds for profiles to gracefully disconnect
341105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // TODO: Introduce a callback mechanism so that each profile can notify
342bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        // BluetoothService when it is done shutting down
343105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mHandler.sendMessageDelayed(
344105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                mHandler.obtainMessage(MESSAGE_FINISH_DISABLE, saveSetting ? 1 : 0, 0), 3000);
345105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        return true;
346105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    }
347105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
348105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
349105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private synchronized void finishDisable(boolean saveSetting) {
350de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        if (mBluetoothState != BluetoothAdapter.STATE_TURNING_OFF) {
351105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return;
3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mEventLoop.stop();
354d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        tearDownNativeDataNative();
3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        disableNative();
3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // mark in progress bondings as cancelled
3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (String address : mBondState.listInState(BluetoothDevice.BOND_BONDING)) {
359005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            mBondState.setBondState(address, BluetoothDevice.BOND_NONE,
3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // update mode
364de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        Intent intent = new Intent(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
365de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        intent.putExtra(BluetoothAdapter.EXTRA_SCAN_MODE, BluetoothAdapter.SCAN_MODE_NONE);
3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.sendBroadcast(intent, BLUETOOTH_PERM);
3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
368105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mIsDiscovering = false;
369bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mAdapterProperties.clear();
37024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        mServiceRecordToPid.clear();
371105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (saveSetting) {
3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            persistBluetoothOnSetting(false);
3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
375105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
376de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        setBluetoothState(BluetoothAdapter.STATE_OFF);
377105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
378105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Log bluetooth off to battery stats.
379105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        long ident = Binder.clearCallingIdentity();
380105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        try {
381105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            mBatteryStats.noteBluetoothOff();
382105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        } catch (RemoteException e) {
383105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        } finally {
384105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            Binder.restoreCallingIdentity(ident);
385105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
386997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly
387997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        if (mRestart) {
388997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly            mRestart = false;
389997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly            enable();
390997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        }
3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
393105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    /** Bring up BT and persist BT on in settings */
394105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    public boolean enable() {
395105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        return enable(true);
3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Enable this Bluetooth device, asynchronously.
4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * This turns on/off the underlying hardware.
4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
402105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project     * @param saveSetting If true, persist the new state of BT in settings
403105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project     * @return True on success (so far)
4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
405105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    public synchronized boolean enable(boolean saveSetting) {
4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Airplane mode can prevent Bluetooth radio from being turned on.
41044303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        if (mIsAirplaneSensitive && isAirplaneModeOn() && !mIsAirplaneToggleable) {
4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
413de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        if (mBluetoothState != BluetoothAdapter.STATE_OFF) {
4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mEnableThread != null && mEnableThread.isAlive()) {
4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
419de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        setBluetoothState(BluetoothAdapter.STATE_TURNING_ON);
420105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mEnableThread = new EnableThread(saveSetting);
4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mEnableThread.start();
4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
425997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly    /** Forcibly restart Bluetooth if it is on */
426997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly    /* package */ synchronized void restart() {
427de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        if (mBluetoothState != BluetoothAdapter.STATE_ON) {
428997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly            return;
429997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        }
430997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        mRestart = true;
431997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        if (!disable(false)) {
432997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly            mRestart = false;
433997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly        }
434d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
435997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly
436105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private synchronized void setBluetoothState(int state) {
437105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        if (state == mBluetoothState) {
438105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return;
439105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
440105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
441105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        if (DBG) log("Bluetooth state " + mBluetoothState + " -> " + state);
442105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
443de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
444de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, mBluetoothState);
445de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        intent.putExtra(BluetoothAdapter.EXTRA_STATE, state);
446105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
447105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
448105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mBluetoothState = state;
449105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
450105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mContext.sendBroadcast(intent, BLUETOOTH_PERM);
451105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    }
452105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final Handler mHandler = new Handler() {
4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void handleMessage(Message msg) {
4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            switch (msg.what) {
457105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            case MESSAGE_REGISTER_SDP_RECORDS:
4588c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh                if (!isEnabledInternal()) {
459bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    return;
460bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                }
461bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                // SystemService.start() forks sdptool to register service
462bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                // records. It can fail to register some records if it is
463bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                // forked multiple times in a row, probably because there is
464bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                // some race in sdptool or bluez when operated in parallel.
465bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                // As a workaround, delay 500ms between each fork of sdptool.
466bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                // TODO: Don't fork sdptool in order to regsiter service
467bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                // records, use a DBUS call instead.
468bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                switch (msg.arg1) {
469bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                case 1:
47077b4ad0e496941a28382eb938a05831f1f8d2d4aJaikumar Ganesh                    Log.d(TAG, "Registering hfag record");
47177b4ad0e496941a28382eb938a05831f1f8d2d4aJaikumar Ganesh                    SystemService.start("hfag");
472bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    mHandler.sendMessageDelayed(
473bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                            mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS, 2, -1), 500);
474bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    break;
475bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                case 2:
47677b4ad0e496941a28382eb938a05831f1f8d2d4aJaikumar Ganesh                    Log.d(TAG, "Registering hsag record");
47777b4ad0e496941a28382eb938a05831f1f8d2d4aJaikumar Ganesh                    SystemService.start("hsag");
478bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    mHandler.sendMessageDelayed(
479bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                            mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS, 3, -1), 500);
480bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    break;
481bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                case 3:
482bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    Log.d(TAG, "Registering opush record");
48303c707ab6fc97e99b1603b8d6edc604dbea3cd6fNick Pelly                    SystemService.start("opush");
484bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    mHandler.sendMessageDelayed(
485bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                            mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS, 4, -1), 500);
486bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    break;
487bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                case 4:
488bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    Log.d(TAG, "Registering pbap record");
48967542964876aa7e4216e8f69f21dda68e7463b9aJaikumar Ganesh                    SystemService.start("pbap");
490bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                    break;
4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
492105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                break;
493105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            case MESSAGE_FINISH_DISABLE:
494105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                finishDisable(msg.arg1 != 0);
495105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                break;
4961caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            case MESSAGE_UUID_INTENT:
4971caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh                String address = (String)msg.obj;
49816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (address != null) {
4991caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh                    sendUuidIntent(address);
50016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    makeServiceChannelCallbacks(address);
50116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                }
5021caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh                break;
50312835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            case MESSAGE_DISCOVERABLE_TIMEOUT:
50412835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                int mode = msg.arg1;
5058c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh                if (isEnabledInternal()) {
50612835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                    // TODO: Switch back to the previous scan mode
50712835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                    // This is ok for now, because we only use
50812835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                    // CONNECTABLE and CONNECTABLE_DISCOVERABLE
50912835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                    setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE, -1);
51012835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                }
51112835478ee687a493d1b5882e67b6725bd539c26Nick Pelly                break;
5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private EnableThread mEnableThread;
5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private class EnableThread extends Thread {
5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final boolean mSaveSetting;
520105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        public EnableThread(boolean saveSetting) {
5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mSaveSetting = saveSetting;
5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void run() {
5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean res = (enableNative() == 0);
5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (res) {
526b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                int retryCount = 2;
527b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                boolean running = false;
528b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                while ((retryCount-- > 0) && !running) {
529b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    mEventLoop.start();
530105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    // it may take a momement for the other thread to do its
531b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    // thing.  Check periodically for a while.
532b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    int pollCount = 5;
533b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    while ((pollCount-- > 0) && !running) {
534b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                        if (mEventLoop.isEventLoopRunning()) {
535b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                            running = true;
536b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                            break;
537b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                        }
538b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                        try {
539b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                            Thread.sleep(100);
540b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                        } catch (InterruptedException e) {}
541b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    }
542b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                }
543b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                if (!running) {
544b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    log("bt EnableThread giving up");
545b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    res = false;
546b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                    disableNative();
547b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project                }
5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (res) {
552d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                if (!setupNativeDataNative()) {
553d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                    return;
554d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                }
5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mSaveSetting) {
5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    persistBluetoothOnSetting(true);
5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mIsDiscovering = false;
559c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                mBondState.readAutoPairingData();
5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mBondState.loadBondState();
5619b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                initProfileState();
562bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                mHandler.sendMessageDelayed(
563bc1fc05c1b3e8c407fa07b25777bf577d5285f49Nick Pelly                        mHandler.obtainMessage(MESSAGE_REGISTER_SDP_RECORDS, 1, -1), 3000);
5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
565105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                // Log bluetooth on to battery stats.
566105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                long ident = Binder.clearCallingIdentity();
567105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                try {
568105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    mBatteryStats.noteBluetoothOn();
569105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                } catch (RemoteException e) {
570105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                } finally {
571105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    Binder.restoreCallingIdentity(ident);
572105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                }
5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
574105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
575105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            mEnableThread = null;
576105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
577105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            setBluetoothState(res ?
578de893f550301a60274e87aa8168225e7a7a42184Nick Pelly                              BluetoothAdapter.STATE_ON :
579de893f550301a60274e87aa8168225e7a7a42184Nick Pelly                              BluetoothAdapter.STATE_OFF);
580105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
581b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            if (res) {
582105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                // Update mode
583d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                String[] propVal = {"Pairable", getProperty("Pairable")};
584d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                mEventLoop.onPropertyChanged(propVal);
585b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            }
586b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project
58744303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey            if (mIsAirplaneSensitive && isAirplaneModeOn() && !mIsAirplaneToggleable) {
5885c43f735d94a538dc273c8f859d1100a7cdd5c71Daisuke Miyakawa                disable(false);
5895c43f735d94a538dc273c8f859d1100a7cdd5c71Daisuke Miyakawa            }
5905c43f735d94a538dc273c8f859d1100a7cdd5c71Daisuke Miyakawa
5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void persistBluetoothOnSetting(boolean bluetoothOn) {
5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long origCallerIdentityToken = Binder.clearCallingIdentity();
5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.BLUETOOTH_ON,
5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                bluetoothOn ? 1 : 0);
5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Binder.restoreCallingIdentity(origCallerIdentityToken);
5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* package */ BondState getBondState() {
6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mBondState;
6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** local cache of bonding state.
6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* we keep our own state to track the intermediate state BONDING, which
6079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* bluez does not track.
6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * All addreses must be passed in upper case.
6099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
6109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public class BondState {
6119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final HashMap<String, Integer> mState = new HashMap<String, Integer>();
6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final HashMap<String, Integer> mPinAttempt = new HashMap<String, Integer>();
613c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh
614c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        private static final String AUTO_PAIRING_BLACKLIST =
615c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            "/etc/bluetooth/auto_pairing.conf";
616c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        private static final String DYNAMIC_AUTO_PAIRING_BLACKLIST =
617c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            "/data/misc/bluetooth/dynamic_auto_pairing.conf";
618c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        private ArrayList<String>  mAutoPairingAddressBlacklist;
619c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        private ArrayList<String> mAutoPairingExactNameBlacklist;
620c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        private ArrayList<String> mAutoPairingPartialNameBlacklist;
621c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        // Addresses added to blacklist dynamically based on usage.
622c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        private ArrayList<String> mAutoPairingDynamicAddressBlacklist;
623c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh
624482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh
6252092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        // If this is an outgoing connection, store the address.
6262092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        // There can be only 1 pending outgoing connection at a time,
6272092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        private String mPendingOutgoingBonding;
6282092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
6292092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        private synchronized void setPendingOutgoingBonding(String address) {
6302092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh            mPendingOutgoingBonding = address;
6312092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        }
6322092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
6332092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        public synchronized String getPendingOutgoingBonding() {
6342092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh            return mPendingOutgoingBonding;
6352092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        }
6362092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
6379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized void loadBondState() {
638de893f550301a60274e87aa8168225e7a7a42184Nick Pelly            if (mBluetoothState != BluetoothAdapter.STATE_TURNING_ON) {
6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
641d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            String []bonds = null;
642b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh            String val = getPropertyInternal("Devices");
643d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            if (val != null) {
644d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                bonds = val.split(",");
645d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            }
6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (bonds == null) {
6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
6489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mState.clear();
6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (DBG) log("found " + bonds.length + " bonded devices");
651d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            for (String device : bonds) {
652d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                mState.put(getAddressFromObjectPath(device).toUpperCase(),
653d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                        BluetoothDevice.BOND_BONDED);
6549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized void setBondState(String address, int state) {
6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            setBondState(address, state, 0);
6599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /** reason is ignored unless state == BOND_NOT_BONDED */
6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized void setBondState(String address, int state, int reason) {
6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int oldState = getBondState(address);
6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (oldState == state) {
6659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6672092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
6682092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh            // Check if this was an pending outgoing bonding.
6692092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh            // If yes, reset the state.
6702092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh            if (oldState == BluetoothDevice.BOND_BONDING) {
6712092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh                if (address.equals(mPendingOutgoingBonding)) {
6722092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh                    mPendingOutgoingBonding = null;
6732092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh                }
6742092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh            }
6752092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
6769b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            if (state == BluetoothDevice.BOND_BONDED) {
6779b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                addProfileState(address);
6789b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            } else if (state == BluetoothDevice.BOND_NONE) {
6799b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh                removeProfileState(address);
6809b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            }
6819b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
682c3ee99d9eb7e8b4b20c2b8f1c548373e1017e0d3Jaikumar Ganesh            // HID is handled by BluetoothService, other profiles
683c3ee99d9eb7e8b4b20c2b8f1c548373e1017e0d3Jaikumar Ganesh            // will be handled by their respective services.
684c3ee99d9eb7e8b4b20c2b8f1c548373e1017e0d3Jaikumar Ganesh            setInitialInputDevicePriority(mAdapter.getRemoteDevice(address), state);
685c3ee99d9eb7e8b4b20c2b8f1c548373e1017e0d3Jaikumar Ganesh
6869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (DBG) log(address + " bond state " + oldState + " -> " + state + " (" +
6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                         reason + ")");
688005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            Intent intent = new Intent(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
689005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
690005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            intent.putExtra(BluetoothDevice.EXTRA_BOND_STATE, state);
691005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            intent.putExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, oldState);
692005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            if (state == BluetoothDevice.BOND_NONE) {
6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (reason <= 0) {
6949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Log.w(TAG, "setBondState() called to unbond device, but reason code is " +
6959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                          "invalid. Overriding reason code with BOND_RESULT_REMOVED");
6969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    reason = BluetoothDevice.UNBOND_REASON_REMOVED;
6979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
698005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly                intent.putExtra(BluetoothDevice.EXTRA_REASON, reason);
6999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mState.remove(address);
7009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
7019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mState.put(address, state);
7029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mContext.sendBroadcast(intent, BLUETOOTH_PERM);
7059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public boolean isAutoPairingBlacklisted(String address) {
708c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            if (mAutoPairingAddressBlacklist != null) {
709c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                for (String blacklistAddress : mAutoPairingAddressBlacklist) {
710c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    if (address.startsWith(blacklistAddress)) return true;
711c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                }
7129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
713482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh
714c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            if (mAutoPairingDynamicAddressBlacklist != null) {
715c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                for (String blacklistAddress: mAutoPairingDynamicAddressBlacklist) {
716c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    if (address.equals(blacklistAddress)) return true;
717c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                }
718c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            }
719482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh            String name = getRemoteName(address);
720482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh            if (name != null) {
721c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                if (mAutoPairingExactNameBlacklist != null) {
722c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    for (String blacklistName : mAutoPairingExactNameBlacklist) {
723c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        if (name.equals(blacklistName)) return true;
724c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    }
725738ed80262aa26128924c51f59ffd49e1163eb8dJaikumar Ganesh                }
726738ed80262aa26128924c51f59ffd49e1163eb8dJaikumar Ganesh
727c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                if (mAutoPairingPartialNameBlacklist != null) {
728c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    for (String blacklistName : mAutoPairingPartialNameBlacklist) {
729c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        if (name.startsWith(blacklistName)) return true;
730c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    }
731482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh                }
732482d54bb0cd9e00fd929185c31fea3ad845d97bcJaikumar Ganesh            }
7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized int getBondState(String address) {
7379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Integer state = mState.get(address);
7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (state == null) {
739005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly                return BluetoothDevice.BOND_NONE;
7409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return state.intValue();
7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
744e5d93b7ed983f98855555d560faf060836f1a52fJaikumar Ganesh        /*package*/ synchronized String[] listInState(int state) {
7459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ArrayList<String> result = new ArrayList<String>(mState.size());
7469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (Map.Entry<String, Integer> e : mState.entrySet()) {
7479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (e.getValue().intValue() == state) {
7489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    result.add(e.getKey());
7499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
7509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return result.toArray(new String[result.size()]);
7529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized void addAutoPairingFailure(String address) {
755c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            if (mAutoPairingDynamicAddressBlacklist == null) {
756c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                mAutoPairingDynamicAddressBlacklist = new ArrayList<String>();
7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
758c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh
759c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            updateAutoPairingData(address);
760c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            mAutoPairingDynamicAddressBlacklist.add(address);
7619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized boolean isAutoPairingAttemptsInProgress(String address) {
7649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return getAttempt(address) != 0;
7659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized void clearPinAttempts(String address) {
7689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mPinAttempt.remove(address);
7699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized boolean hasAutoPairingFailed(String address) {
772c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            if (mAutoPairingDynamicAddressBlacklist == null) return false;
773c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh
774c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            return mAutoPairingDynamicAddressBlacklist.contains(address);
7759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized int getAttempt(String address) {
7789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Integer attempt = mPinAttempt.get(address);
7799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (attempt == null) {
7809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return 0;
7819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return attempt.intValue();
7839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public synchronized void attempt(String address) {
7869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Integer attempt = mPinAttempt.get(address);
7879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int newAttempt;
7889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (attempt == null) {
7899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                newAttempt = 1;
7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
7919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                newAttempt = attempt.intValue() + 1;
7929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mPinAttempt.put(address, new Integer(newAttempt));
7949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
796c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        private void copyAutoPairingData() {
797c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            File file = null;
798c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            FileInputStream in = null;
799c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            FileOutputStream out = null;
800c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            try {
801c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                file = new File(DYNAMIC_AUTO_PAIRING_BLACKLIST);
802c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                if (file.exists()) return;
803c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh
804c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                in = new FileInputStream(AUTO_PAIRING_BLACKLIST);
805c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                out= new FileOutputStream(DYNAMIC_AUTO_PAIRING_BLACKLIST);
806c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh
807c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                byte[] buf = new byte[1024];
808c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                int len;
809c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                while ((len = in.read(buf)) > 0) {
810c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    out.write(buf, 0, len);
811c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                }
812c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            } catch (FileNotFoundException e) {
813c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                log("FileNotFoundException: in copyAutoPairingData");
814c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            } catch (IOException e) {
815c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                log("IOException: in copyAutoPairingData");
816c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            } finally {
817c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                 try {
818c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                     if (in != null) in.close();
819c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                     if (out != null) out.close();
820c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                 } catch (IOException e) {}
821c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            }
822c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        }
823c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh
824c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        public void readAutoPairingData() {
825c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            if (mAutoPairingAddressBlacklist != null) return;
826c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            copyAutoPairingData();
827c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            FileInputStream fstream = null;
828c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            try {
829c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                fstream = new FileInputStream(DYNAMIC_AUTO_PAIRING_BLACKLIST);
830c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                DataInputStream in = new DataInputStream(fstream);
831c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                BufferedReader file = new BufferedReader(new InputStreamReader(in));
832c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                String line;
833c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                while((line = file.readLine()) != null) {
834c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    line = line.trim();
835c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    if (line.length() == 0 || line.startsWith("//")) continue;
836c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    String[] value = line.split("=");
837c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    if (value != null && value.length == 2) {
838c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        String[] val = value[1].split(",");
839c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        if (value[0].equalsIgnoreCase("AddressBlacklist")) {
840c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                            mAutoPairingAddressBlacklist =
841c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                                new ArrayList<String>(Arrays.asList(val));
842c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        } else if (value[0].equalsIgnoreCase("ExactNameBlacklist")) {
843c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                            mAutoPairingExactNameBlacklist =
844c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                                new ArrayList<String>(Arrays.asList(val));
845c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        } else if (value[0].equalsIgnoreCase("PartialNameBlacklist")) {
846c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                            mAutoPairingPartialNameBlacklist =
847c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                                new ArrayList<String>(Arrays.asList(val));
848c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        } else if (value[0].equalsIgnoreCase("DynamicAddressBlacklist")) {
849c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                            mAutoPairingDynamicAddressBlacklist =
850c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                                new ArrayList<String>(Arrays.asList(val));
851c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        } else {
852c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                            Log.e(TAG, "Error parsing Auto pairing blacklist file");
853c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        }
854c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    }
855c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                }
856c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            } catch (FileNotFoundException e) {
857c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                log("FileNotFoundException: readAutoPairingData" + e.toString());
858c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            } catch (IOException e) {
859c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                log("IOException: readAutoPairingData" + e.toString());
860c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            } finally {
861c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                if (fstream != null) {
862c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    try {
863c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        fstream.close();
864c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    } catch (IOException e) {
865c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        // Ignore
866c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    }
867c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                }
868c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            }
869c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        }
870c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh
871c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        // This function adds a bluetooth address to the auto pairing blacklis
872c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        // file. These addresses are added to DynamicAddressBlacklistSection
873c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        private void updateAutoPairingData(String address) {
874c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            BufferedWriter out = null;
875c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            try {
876c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                out = new BufferedWriter(new FileWriter(DYNAMIC_AUTO_PAIRING_BLACKLIST, true));
877c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                StringBuilder str = new StringBuilder();
878c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                if (mAutoPairingDynamicAddressBlacklist.size() == 0) {
879c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    str.append("DynamicAddressBlacklist=");
880c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                }
881c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                str.append(address);
882c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                str.append(",");
883c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                out.write(str.toString());
884c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            } catch (FileNotFoundException e) {
885c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                log("FileNotFoundException: updateAutoPairingData" + e.toString());
886c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            } catch (IOException e) {
887c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                log("IOException: updateAutoPairingData" + e.toString());
888c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            } finally {
889c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                if (out != null) {
890c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    try {
891c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        out.close();
892c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    } catch (IOException e) {
893c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                        // Ignore
894c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                    }
895c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh                }
896c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh            }
897c06fe59cb5a1bdd2a87d1aff3e35edf29a859979Jaikumar Ganesh        }
8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static String toBondStateString(int bondState) {
9019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        switch (bondState) {
902005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        case BluetoothDevice.BOND_NONE:
9039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "not bonded";
9049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case BluetoothDevice.BOND_BONDING:
9059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "bonding";
9069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case BluetoothDevice.BOND_BONDED:
9079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "bonded";
9089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        default:
9099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "??????";
9109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9139519ce75f15ba287a641166c1b7ed10f2aa73f74Jaikumar Ganesh    /*package*/ synchronized boolean isAdapterPropertiesEmpty() {
9149519ce75f15ba287a641166c1b7ed10f2aa73f74Jaikumar Ganesh        return mAdapterProperties.isEmpty();
9159519ce75f15ba287a641166c1b7ed10f2aa73f74Jaikumar Ganesh    }
9169519ce75f15ba287a641166c1b7ed10f2aa73f74Jaikumar Ganesh
917d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /*package*/synchronized void getAllProperties() {
9188c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
9199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
920bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mAdapterProperties.clear();
921d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
922d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String properties[] = (String [])getAdapterPropertiesNative();
923d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        // The String Array consists of key-value pairs.
924d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (properties == null) {
925d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            Log.e(TAG, "*Error*: GetAdapterProperties returned NULL");
926d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return;
927d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
928d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
9298bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh        for (int i = 0; i < properties.length; i++) {
9308bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            String name = properties[i];
931efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh            String newValue = null;
9328bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            int len;
9338bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            if (name == null) {
9348bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                Log.e(TAG, "Error:Adapter Property at index" + i + "is null");
9358bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                continue;
9368bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            }
9377a9de8b425954e4039053038e4ec1762b866c83cDanica Chang            if (name.equals("Devices") || name.equals("UUIDs")) {
938efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                StringBuilder str = new StringBuilder();
9398bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                len = Integer.valueOf(properties[++i]);
9408bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                for (int j = 0; j < len; j++) {
941efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                    str.append(properties[++i]);
942efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                    str.append(",");
943efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                }
944efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                if (len > 0) {
945efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                    newValue = str.toString();
9468bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                }
9478bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            } else {
9488bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                newValue = properties[++i];
9498bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            }
950bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            mAdapterProperties.put(name, newValue);
951d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
952d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
953d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        // Add adapter object path property.
954d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String adapterPath = getAdapterPathNative();
955d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (adapterPath != null)
956bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            mAdapterProperties.put("ObjectPath", adapterPath + "/dev_");
9579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
959d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ synchronized void setProperty(String name, String value) {
960bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mAdapterProperties.put(name, value);
9619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean setName(String name) {
9649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
9659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
9669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (name == null) {
9679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
9689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
969d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setPropertyString("Name", name);
9709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
972d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    //TODO(): setPropertyString, setPropertyInteger, setPropertyBoolean
973d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    // Either have a single property function with Object as the parameter
974d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    // or have a function for each property and then obfuscate in the JNI layer.
975d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    // The following looks dirty.
976d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private boolean setPropertyString(String key, String value) {
9779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
9788c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
979d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setAdapterPropertyStringNative(key, value);
9809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
982d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private boolean setPropertyInteger(String key, int value) {
983d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
9848c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
985d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setAdapterPropertyIntegerNative(key, value);
986d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
9879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
988d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private boolean setPropertyBoolean(String key, boolean value) {
989d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
9908c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
991d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setAdapterPropertyBooleanNative(key, value ? 1 : 0);
9929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
994d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /**
995d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Set the discoverability window for the device.  A timeout of zero
996d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * makes the device permanently discoverable (if the device is
997d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * discoverable).  Setting the timeout to a nonzero value does not make
998d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * a device discoverable; you need to call setMode() to make the device
999d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * explicitly discoverable.
1000d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     *
1001d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * @param timeout_s The discoverable timeout in seconds.
1002d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     */
1003d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized boolean setDiscoverableTimeout(int timeout) {
10049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
10059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
1006d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setPropertyInteger("DiscoverableTimeout", timeout);
10079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
100912835478ee687a493d1b5882e67b6725bd539c26Nick Pelly    public synchronized boolean setScanMode(int mode, int duration) {
101018b1e79a123b979d25bfa5d0b0ee5d0382dbd64bNick Pelly        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS,
101118b1e79a123b979d25bfa5d0b0ee5d0382dbd64bNick Pelly                                                "Need WRITE_SECURE_SETTINGS permission");
1012de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        boolean pairable = false;
1013de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        boolean discoverable = false;
101412835478ee687a493d1b5882e67b6725bd539c26Nick Pelly
1015de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        switch (mode) {
1016de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.SCAN_MODE_NONE:
101712835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            mHandler.removeMessages(MESSAGE_DISCOVERABLE_TIMEOUT);
1018d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            pairable = false;
1019d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            discoverable = false;
1020de893f550301a60274e87aa8168225e7a7a42184Nick Pelly            break;
1021de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
102212835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            mHandler.removeMessages(MESSAGE_DISCOVERABLE_TIMEOUT);
1023d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            pairable = true;
1024d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            discoverable = false;
1025005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            break;
1026de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
102712835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            mHandler.removeMessages(MESSAGE_DISCOVERABLE_TIMEOUT);
1028d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            pairable = true;
1029d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            discoverable = true;
103012835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            Message msg = mHandler.obtainMessage(MESSAGE_DISCOVERABLE_TIMEOUT);
103112835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            mHandler.sendMessageDelayed(msg, duration * 1000);
103212835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            if (DBG) Log.d(TAG, "BT Discoverable for " + duration + " seconds");
1033005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            break;
1034de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        default:
1035de893f550301a60274e87aa8168225e7a7a42184Nick Pelly            Log.w(TAG, "Requested invalid scan mode " + mode);
1036de893f550301a60274e87aa8168225e7a7a42184Nick Pelly            return false;
1037d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
1038d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        setPropertyBoolean("Pairable", pairable);
1039d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        setPropertyBoolean("Discoverable", discoverable);
10409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1041d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return true;
10429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1044b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh    /*package*/ synchronized String getProperty(String name) {
1045b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh        if (!isEnabledInternal()) return null;
1046b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh        return getPropertyInternal(name);
1047b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh    }
1048b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh
1049b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh    /*package*/ synchronized String getPropertyInternal(String name) {
1050bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        if (!mAdapterProperties.isEmpty())
1051bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            return mAdapterProperties.get(name);
1052d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        getAllProperties();
1053bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        return mAdapterProperties.get(name);
10549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1056d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized String getAddress() {
1057d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1058d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return getProperty("Address");
10599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1061d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized String getName() {
10629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1063d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return getProperty("Name");
10649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1067d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Returns the user-friendly name of a remote device.  This value is
1068d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * returned from our local cache, which is updated when onPropertyChange
1069d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * event is received.
1070d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Do not expect to retrieve the updated remote name immediately after
1071d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * changing the name on the remote device.
10729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1073d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * @param address Bluetooth address of remote device.
1074d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     *
1075d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * @return The user-friendly name of the specified remote device.
10769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1077d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized String getRemoteName(String address) {
1078d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1079005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1080d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return null;
1081d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
108255929a958bf0e482c8e4d7df3dd75957f1e9d871Jaikumar Ganesh        return getRemoteDeviceProperty(address, "Name");
10839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
10869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Get the discoverability window for the device.  A timeout of zero
10879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * means that the device is permanently discoverable (if the device is
10889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * in the discoverable mode).
10899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
10909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The discoverability window of the device, in seconds.  A negative
10919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         value indicates an error.
10929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
10939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized int getDiscoverableTimeout() {
10949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1095d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String timeout = getProperty("DiscoverableTimeout");
1096d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (timeout != null)
1097d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh           return Integer.valueOf(timeout);
1098d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        else
1099d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return -1;
11009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized int getScanMode() {
11039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
11048c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal())
1105de893f550301a60274e87aa8168225e7a7a42184Nick Pelly            return BluetoothAdapter.SCAN_MODE_NONE;
1106d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1107d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        boolean pairable = getProperty("Pairable").equals("true");
1108d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        boolean discoverable = getProperty("Discoverable").equals("true");
1109d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return bluezStringToScanMode (pairable, discoverable);
11109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1112d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized boolean startDiscovery() {
11139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
11149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
11158c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
11168c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1117d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return startDiscoveryNative();
11189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1120d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized boolean cancelDiscovery() {
11219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
11229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
11238c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
11248c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1125d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return stopDiscoveryNative();
1126d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
1127d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1128d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized boolean isDiscovering() {
1129d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1130d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return mIsDiscovering;
1131d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
1132d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
1133d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ void setIsDiscovering(boolean isDiscovering) {
1134d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mIsDiscovering = isDiscovering;
11359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean createBond(String address) {
11389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
11399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
11408c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
11418c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1142005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
11439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
11449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        address = address.toUpperCase();
11469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11472092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        if (mBondState.getPendingOutgoingBonding() != null) {
11489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            log("Ignoring createBond(): another device is bonding");
11499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // a different device is currently bonding, fail
11509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
11519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Check for bond state only if we are not performing auto
11549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // pairing exponential back-off attempts.
11559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mBondState.isAutoPairingAttemptsInProgress(address) &&
1156005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly                mBondState.getBondState(address) != BluetoothDevice.BOND_NONE) {
11579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            log("Ignoring createBond(): this device is already bonding or bonded");
11589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
11599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11613fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        if (address.equals(mDockAddress)) {
11623fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            if (!writeDockPin()) {
11633fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                log("Error while writing Pin for the dock");
11643fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                return false;
11653fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            }
11663fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        }
11673fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
1168d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (!createPairedDeviceNative(address, 60000 /* 1 minute */)) {
11699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
11709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11722092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        mBondState.setPendingOutgoingBonding(address);
11739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mBondState.setBondState(address, BluetoothDevice.BOND_BONDING);
11742092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
11759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
11769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean cancelBondProcess(String address) {
11799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
11809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
11818c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
11828c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1183005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
11849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
11859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        address = address.toUpperCase();
11879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mBondState.getBondState(address) != BluetoothDevice.BOND_BONDING) {
11889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
11899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1191005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        mBondState.setBondState(address, BluetoothDevice.BOND_NONE,
11929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
1193d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        cancelDeviceCreationNative(address);
11949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
11959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean removeBond(String address) {
11989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
11999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
12008c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
12018c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1202005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
12039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
12049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1205f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
12069b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (state != null) {
1207f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            state.sendMessage(BluetoothDeviceProfileState.UNPAIR);
12089b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            return true;
12099b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        } else {
12109b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            return false;
12119b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
12129b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
12139b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
12149b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public synchronized boolean removeBondInternal(String address) {
1215d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return removeDeviceNative(getObjectPathFromAddress(address));
12169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized String[] listBonds() {
12199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
12209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mBondState.listInState(BluetoothDevice.BOND_BONDED);
12219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized int getBondState(String address) {
12249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1225005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1226b24e11baac589fe16426f2d243b460ab84991c7bNick Pelly            return BluetoothDevice.ERROR;
12279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mBondState.getBondState(address.toUpperCase());
12299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12313fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    public synchronized boolean isBluetoothDock(String address) {
12326e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh        SharedPreferences sp = mContext.getSharedPreferences(SHARED_PREFERENCES_NAME,
12336e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                mContext.MODE_PRIVATE);
12346e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh
12356e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh        return sp.contains(SHARED_PREFERENCE_DOCK_ADDRESS + address);
12363fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    }
12373fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
1238545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh    public synchronized boolean connectInputDevice(BluetoothDevice device) {
1239545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1240545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh                                                "Need BLUETOOTH_ADMIN permission");
1241545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh
1242545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        String objectPath = getObjectPathFromAddress(device.getAddress());
124305a1863cebcc8e318283f3f4a49ba69d83b62866Jaikumar Ganesh        if (objectPath == null ||
124405a1863cebcc8e318283f3f4a49ba69d83b62866Jaikumar Ganesh            getInputDeviceState(device) != BluetoothInputDevice.STATE_DISCONNECTED ||
1245545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh            getInputDevicePriority(device) == BluetoothInputDevice.PRIORITY_OFF) {
1246545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh            return false;
1247545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        }
1248de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh        BluetoothDeviceProfileState state = mDeviceProfileState.get(device.getAddress());
1249de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh        if (state != null) {
1250de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh            Message msg = new Message();
1251de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh            msg.arg1 = BluetoothDeviceProfileState.CONNECT_HID_OUTGOING;
1252de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh            msg.obj = state;
1253de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh            mHidProfileState.sendMessage(msg);
1254545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh            return true;
1255545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        }
1256545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        return false;
1257545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh    }
1258545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh
1259de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh    public synchronized boolean connectInputDeviceInternal(BluetoothDevice device) {
1260de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh        String objectPath = getObjectPathFromAddress(device.getAddress());
1261de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh        handleInputDeviceStateChange(device, BluetoothInputDevice.STATE_CONNECTING);
1262de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh        if (!connectInputDeviceNative(objectPath)) {
1263de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh            handleInputDeviceStateChange(device, BluetoothInputDevice.STATE_DISCONNECTED);
1264de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh            return false;
1265de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh        }
1266de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh        return true;
1267de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh    }
1268de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh
1269545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh    public synchronized boolean disconnectInputDevice(BluetoothDevice device) {
1270545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1271545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh                                                "Need BLUETOOTH_ADMIN permission");
1272545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh
1273545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        String objectPath = getObjectPathFromAddress(device.getAddress());
1274545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        if (objectPath == null || getConnectedInputDevices().length == 0) {
1275545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh            return false;
1276545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        }
1277de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh        BluetoothDeviceProfileState state = mDeviceProfileState.get(device.getAddress());
1278de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh        if (state != null) {
1279de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh            Message msg = new Message();
1280de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh            msg.arg1 = BluetoothDeviceProfileState.DISCONNECT_HID_OUTGOING;
1281de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh            msg.obj = state;
1282de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh            mHidProfileState.sendMessage(msg);
1283545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh            return true;
1284545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        }
1285545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        return false;
1286545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh    }
1287545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh
1288de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh    public synchronized boolean disconnectInputDeviceInternal(BluetoothDevice device) {
1289de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh        String objectPath = getObjectPathFromAddress(device.getAddress());
1290de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh        handleInputDeviceStateChange(device, BluetoothInputDevice.STATE_DISCONNECTING);
1291de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh        if (!disconnectInputDeviceNative(objectPath)) {
1292de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh            handleInputDeviceStateChange(device, BluetoothInputDevice.STATE_CONNECTED);
1293de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh            return false;
1294de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh        }
1295de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh        return true;
1296de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh    }
1297de07503a382e81ba82f4cd4dee81ff2fbf3295bcJaikumar Ganesh
1298545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh    public synchronized int getInputDeviceState(BluetoothDevice device) {
1299545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1300545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh
1301545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        if (mInputDevices.get(device) == null) {
1302545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh            return BluetoothInputDevice.STATE_DISCONNECTED;
1303545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        }
1304df7627db715a7a2e7f646f02a07caf2347bb90b8Adam Powell        return mInputDevices.get(device);
1305545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh    }
1306545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh
1307545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh    public synchronized BluetoothDevice[] getConnectedInputDevices() {
1308545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1309545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        Set<BluetoothDevice> devices = lookupInputDevicesMatchingStates(
1310545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh            new int[] {BluetoothInputDevice.STATE_CONNECTED});
1311545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        return devices.toArray(new BluetoothDevice[devices.size()]);
1312545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh    }
1313545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh
1314545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh    public synchronized int getInputDevicePriority(BluetoothDevice device) {
1315545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1316545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        return Settings.Secure.getInt(mContext.getContentResolver(),
1317545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh                Settings.Secure.getBluetoothInputDevicePriorityKey(device.getAddress()),
1318545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh                BluetoothInputDevice.PRIORITY_UNDEFINED);
1319545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh    }
1320545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh
1321545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh    public synchronized boolean setInputDevicePriority(BluetoothDevice device, int priority) {
1322545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1323545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh                                                "Need BLUETOOTH_ADMIN permission");
1324545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        if (!BluetoothAdapter.checkBluetoothAddress(device.getAddress())) {
1325545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh            return false;
1326545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        }
1327545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        return Settings.Secure.putInt(mContext.getContentResolver(),
1328545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh                Settings.Secure.getBluetoothInputDevicePriorityKey(device.getAddress()),
1329545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh                priority);
1330545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh    }
1331545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh
1332545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh    /*package*/synchronized Set<BluetoothDevice> lookupInputDevicesMatchingStates(int[] states) {
1333545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        Set<BluetoothDevice> inputDevices = new HashSet<BluetoothDevice>();
1334545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        if (mInputDevices.isEmpty()) {
1335545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh            return inputDevices;
1336545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        }
1337545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        for (BluetoothDevice device: mInputDevices.keySet()) {
1338545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh            int inputDeviceState = getInputDeviceState(device);
1339545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh            for (int state : states) {
1340545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh                if (state == inputDeviceState) {
1341545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh                    inputDevices.add(device);
1342545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh                    break;
1343545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh                }
1344545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh            }
1345545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        }
1346545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        return inputDevices;
1347545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh    }
1348545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh
1349545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh    private synchronized void handleInputDeviceStateChange(BluetoothDevice device, int state) {
1350545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        int prevState;
1351545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        if (mInputDevices.get(device) == null) {
1352545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh            prevState = BluetoothInputDevice.STATE_DISCONNECTED;
1353545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        } else {
1354545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh            prevState = mInputDevices.get(device);
1355545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        }
1356545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        if (prevState == state) return;
1357545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh
1358545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        mInputDevices.put(device, state);
1359545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh
1360545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        if (getInputDevicePriority(device) >
1361545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh              BluetoothInputDevice.PRIORITY_OFF &&
1362545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh            state == BluetoothInputDevice.STATE_CONNECTING ||
1363545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh            state == BluetoothInputDevice.STATE_CONNECTED) {
1364545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh            // We have connected or attempting to connect.
1365545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh            // Bump priority
1366545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh            setInputDevicePriority(device, BluetoothInputDevice.PRIORITY_AUTO_CONNECT);
1367545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        }
1368545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh
1369545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        Intent intent = new Intent(BluetoothInputDevice.ACTION_INPUT_DEVICE_STATE_CHANGED);
1370545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
1371545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        intent.putExtra(BluetoothInputDevice.EXTRA_PREVIOUS_INPUT_DEVICE_STATE, prevState);
1372545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        intent.putExtra(BluetoothInputDevice.EXTRA_INPUT_DEVICE_STATE, state);
1373545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        mContext.sendBroadcast(intent, BLUETOOTH_PERM);
1374545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh
1375545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        if (DBG) log("InputDevice state : device: " + device + " State:" + prevState + "->" + state);
1376545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh
1377545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh    }
1378545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh
137956d26139659c2414d289194c63860ff27ab80da0Jaikumar Ganesh    /*package*/ void handleInputDevicePropertyChange(String address, boolean connected) {
1380545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        int state = connected ? BluetoothInputDevice.STATE_CONNECTED :
1381545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh            BluetoothInputDevice.STATE_DISCONNECTED;
1382545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        BluetoothDevice device = mAdapter.getRemoteDevice(address);
1383545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh        handleInputDeviceStateChange(device, state);
1384545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh    }
1385545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh
1386c3ee99d9eb7e8b4b20c2b8f1c548373e1017e0d3Jaikumar Ganesh    private void setInitialInputDevicePriority(BluetoothDevice device, int state) {
1387c3ee99d9eb7e8b4b20c2b8f1c548373e1017e0d3Jaikumar Ganesh        switch (state) {
1388c3ee99d9eb7e8b4b20c2b8f1c548373e1017e0d3Jaikumar Ganesh            case BluetoothDevice.BOND_BONDED:
1389c3ee99d9eb7e8b4b20c2b8f1c548373e1017e0d3Jaikumar Ganesh                if (getInputDevicePriority(device) == BluetoothInputDevice.PRIORITY_UNDEFINED) {
1390c3ee99d9eb7e8b4b20c2b8f1c548373e1017e0d3Jaikumar Ganesh                    setInputDevicePriority(device, BluetoothInputDevice.PRIORITY_ON);
1391c3ee99d9eb7e8b4b20c2b8f1c548373e1017e0d3Jaikumar Ganesh                }
1392c3ee99d9eb7e8b4b20c2b8f1c548373e1017e0d3Jaikumar Ganesh                break;
1393c3ee99d9eb7e8b4b20c2b8f1c548373e1017e0d3Jaikumar Ganesh            case BluetoothDevice.BOND_NONE:
1394c3ee99d9eb7e8b4b20c2b8f1c548373e1017e0d3Jaikumar Ganesh                setInputDevicePriority(device, BluetoothInputDevice.PRIORITY_UNDEFINED);
1395c3ee99d9eb7e8b4b20c2b8f1c548373e1017e0d3Jaikumar Ganesh                break;
1396c3ee99d9eb7e8b4b20c2b8f1c548373e1017e0d3Jaikumar Ganesh        }
1397c3ee99d9eb7e8b4b20c2b8f1c548373e1017e0d3Jaikumar Ganesh    }
1398c3ee99d9eb7e8b4b20c2b8f1c548373e1017e0d3Jaikumar Ganesh
13999488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh    /*package*/ boolean isRemoteDeviceInCache(String address) {
1400bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        return (mDeviceProperties.get(address) != null);
14019488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh    }
14029488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh
14039488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh    /*package*/ String[] getRemoteDeviceProperties(String address) {
14048c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return null;
14058c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
14069488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh        String objectPath = getObjectPathFromAddress(address);
14079488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh        return (String [])getDevicePropertiesNative(objectPath);
14089488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh    }
14099488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh
1410d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /*package*/ synchronized String getRemoteDeviceProperty(String address, String property) {
1411bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        Map<String, String> properties = mDeviceProperties.get(address);
1412d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (properties != null) {
1413d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return properties.get(property);
1414d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        } else {
1415d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            // Query for remote device properties, again.
1416d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            // We will need to reload the cache when we switch Bluetooth on / off
1417d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            // or if we crash.
141810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            if (updateRemoteDevicePropertiesCache(address))
1419d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                return getRemoteDeviceProperty(address, property);
14209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1421d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        Log.e(TAG, "getRemoteDeviceProperty: " + property + "not present:" + address);
1422d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return null;
14239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
142510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh    /* package */ synchronized boolean updateRemoteDevicePropertiesCache(String address) {
142610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        String[] propValues = getRemoteDeviceProperties(address);
142710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        if (propValues != null) {
142810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            addRemoteDeviceProperties(address, propValues);
142910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            return true;
143010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        }
143110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        return false;
143210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh    }
143310eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
1434d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ synchronized void addRemoteDeviceProperties(String address, String[] properties) {
1435395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh        /*
1436395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh         * We get a DeviceFound signal every time RSSI changes or name changes.
1437395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh         * Don't create a new Map object every time */
1438bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        Map<String, String> propertyValues = mDeviceProperties.get(address);
1439efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh        if (propertyValues == null) {
1440395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh            propertyValues = new HashMap<String, String>();
1441395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh        }
1442395d1023660c5caedf7888def17f8ad826f51bf8Jaikumar Ganesh
14438bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh        for (int i = 0; i < properties.length; i++) {
14448bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            String name = properties[i];
1445efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh            String newValue = null;
14468bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            int len;
14478bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            if (name == null) {
14488bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                Log.e(TAG, "Error: Remote Device Property at index" + i + "is null");
14498bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                continue;
14508bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            }
14518bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            if (name.equals("UUIDs") || name.equals("Nodes")) {
1452efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                StringBuilder str = new StringBuilder();
14538bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                len = Integer.valueOf(properties[++i]);
14548bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                for (int j = 0; j < len; j++) {
1455efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                    str.append(properties[++i]);
1456efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                    str.append(",");
1457efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                }
1458efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                if (len > 0) {
1459efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh                    newValue = str.toString();
14608bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                }
1461d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            } else {
14628bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh                newValue = properties[++i];
1463d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            }
1464efa33676caf5b7a637fad73cd22c9ef23b68cdc2Jaikumar Ganesh
14658bc8ce44f7e5a720e7b989bdd63bb33da512103bJaikumar Ganesh            propertyValues.put(name, newValue);
14669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1467bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mDeviceProperties.put(address, propertyValues);
146810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
146910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        // We have added a new remote device or updated its properties.
147010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        // Also update the serviceChannel cache.
147110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        updateDeviceServiceChannelCache(address);
14729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1474d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ void removeRemoteDeviceProperties(String address) {
1475bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mDeviceProperties.remove(address);
14769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1478d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ synchronized void setRemoteDeviceProperty(String address, String name,
1479d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                                                              String value) {
1480bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        Map <String, String> propVal = mDeviceProperties.get(address);
1481d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (propVal != null) {
1482d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            propVal.put(name, value);
1483bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            mDeviceProperties.put(address, propVal);
1484d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        } else {
1485d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            Log.e(TAG, "setRemoteDeviceProperty for a device not in cache:" + address);
14869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
14879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1490efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * Sets the remote device trust state.
1491efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     *
1492efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * @return boolean to indicate operation success or fail
1493efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     */
1494efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    public synchronized boolean setTrust(String address, boolean value) {
1495005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1496e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly            mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1497e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly                    "Need BLUETOOTH_ADMIN permission");
1498efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            return false;
1499efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        }
1500efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue
15018c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
15028c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1503efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        return setDevicePropertyBooleanNative(getObjectPathFromAddress(address), "Trusted",
1504efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue                value ? 1 : 0);
1505efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    }
1506efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue
1507efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    /**
1508efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * Gets the remote device trust state as boolean.
1509efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * Note: this value may be
1510efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * retrieved from cache if we retrieved the data before *
1511efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     *
1512efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * @return boolean to indicate trust or untrust state
1513efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     */
1514efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    public synchronized boolean getTrustState(String address) {
1515005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1516efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1517efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            return false;
1518efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        }
1519efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue
1520efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        String val = getRemoteDeviceProperty(address, "Trusted");
1521efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        if (val == null) {
1522efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            return false;
1523efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        } else {
1524efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            return val.equals("true") ? true : false;
1525efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        }
1526efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    }
1527efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue
1528efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    /**
1529d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Gets the remote major, minor classes encoded as a 32-bit
15309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * integer.
15319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
15329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Note: this value is retrieved from cache, because we get it during
15339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *       remote-device discovery.
15349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
15359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return 32-bit integer encoding the remote major, minor, and service
15369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         classes.
15379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
15389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized int getRemoteClass(String address) {
1539005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1540ea600ccfb7568f60377c4abc85f56c80af7fdbfcNick Pelly            mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1541ea600ccfb7568f60377c4abc85f56c80af7fdbfcNick Pelly            return BluetoothClass.ERROR;
15429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1543d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String val = getRemoteDeviceProperty(address, "Class");
1544d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (val == null)
1545d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return BluetoothClass.ERROR;
1546d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        else {
1547d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return Integer.valueOf(val);
1548d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
15499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1550d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
15519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1553dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh     * Gets the UUIDs supported by the remote device
15549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1555dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh     * @return array of 128bit ParcelUuids
15569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1557dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh    public synchronized ParcelUuid[] getRemoteUuids(String address) {
15589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1559005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
15609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return null;
15619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
15621caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        return getUuidFromCache(address);
15631caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    }
15641caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
15651caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    private ParcelUuid[] getUuidFromCache(String address) {
1566d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String value = getRemoteDeviceProperty(address, "UUIDs");
1567dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        if (value == null) return null;
1568dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh
1569dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        String[] uuidStrings = null;
1570d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        // The UUIDs are stored as a "," separated string.
1571dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        uuidStrings = value.split(",");
1572dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        ParcelUuid[] uuids = new ParcelUuid[uuidStrings.length];
1573dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh
1574dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        for (int i = 0; i < uuidStrings.length; i++) {
1575dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh            uuids[i] = ParcelUuid.fromString(uuidStrings[i]);
1576dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        }
1577d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return uuids;
15789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
15799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
158016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    /**
158116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * Connect and fetch new UUID's using SDP.
158216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * The UUID's found are broadcast as intents.
158316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * Optionally takes a uuid and callback to fetch the RFCOMM channel for the
158416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * a given uuid.
158516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * TODO: Don't wait UUID_INTENT_DELAY to broadcast UUID intents on success
158616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * TODO: Don't wait UUID_INTENT_DELAY to handle the failure case for
158716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * callback and broadcast intents.
158816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     */
158916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    public synchronized boolean fetchRemoteUuids(String address, ParcelUuid uuid,
159016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            IBluetoothCallback callback) {
15911caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
15928c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
15938c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
15941caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
15951caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            return false;
15961caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        }
15971caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
159816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        RemoteService service = new RemoteService(address, uuid);
159916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        if (uuid != null && mUuidCallbackTracker.get(service) != null) {
160016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            // An SDP query for this address & uuid is already in progress
160116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            // Do not add this callback for the uuid
160216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            return false;
160316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
160416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
16051caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        if (mUuidIntentTracker.contains(address)) {
16061caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            // An SDP query for this address is already in progress
160716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            // Add this uuid onto the in-progress SDP query
160816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (uuid != null) {
160916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                mUuidCallbackTracker.put(new RemoteService(address, uuid), callback);
161016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
16111caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            return true;
16121caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        }
16131caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
16141caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        boolean ret;
16150e09030977aea8b40fd177139528d4b5637c9771Jaikumar Ganesh        // Just do the SDP if the device is already  created and UUIDs are not
16160e09030977aea8b40fd177139528d4b5637c9771Jaikumar Ganesh        // NULL, else create the device and then do SDP.
16170e09030977aea8b40fd177139528d4b5637c9771Jaikumar Ganesh        if (isRemoteDeviceInCache(address) && getRemoteUuids(address) != null) {
16181caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            String path = getObjectPathFromAddress(address);
16191caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            if (path == null) return false;
16201caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
16211caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            // Use an empty string for the UUID pattern
16221caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            ret = discoverServicesNative(path, "");
16231caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        } else {
16241caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            ret = createDeviceNative(address);
16251caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        }
16261caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
16271caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        mUuidIntentTracker.add(address);
162816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        if (uuid != null) {
162916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            mUuidCallbackTracker.put(new RemoteService(address, uuid), callback);
163016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
16311caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
16321caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        Message message = mHandler.obtainMessage(MESSAGE_UUID_INTENT);
16331caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        message.obj = address;
16341caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        mHandler.sendMessageDelayed(message, UUID_INTENT_DELAY);
16351caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        return ret;
16361caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    }
16371caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
16389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1639d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Gets the rfcomm channel associated with the UUID.
164016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * Pulls records from the cache only.
16419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1642d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * @param address Address of the remote device
1643dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh     * @param uuid ParcelUuid of the service attribute
16449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1645d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * @return rfcomm channel associated with the service attribute
164610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh     *         -1 on error
16479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1648dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh    public int getRemoteServiceChannel(String address, ParcelUuid uuid) {
16499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
16508c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return -1;
16518c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1652005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1653b24e11baac589fe16426f2d243b460ab84991c7bNick Pelly            return BluetoothDevice.ERROR;
16549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
165510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        // Check if we are recovering from a crash.
165610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        if (mDeviceProperties.isEmpty()) {
165710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            if (!updateRemoteDevicePropertiesCache(address))
165810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh                return -1;
165910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        }
166010eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
166110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        Map<ParcelUuid, Integer> value = mDeviceServiceChannelCache.get(address);
166210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        if (value != null && value.containsKey(uuid))
166310eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            return value.get(uuid);
166410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        return -1;
16659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
16669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean setPin(String address, byte[] pin) {
16689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
16699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
16708c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
16718c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
16729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (pin == null || pin.length <= 0 || pin.length > 16 ||
1673005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            !BluetoothAdapter.checkBluetoothAddress(address)) {
16749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
16759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
16769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        address = address.toUpperCase();
16779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
16789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (data == null) {
16799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.w(TAG, "setPin(" + address + ") called but no native data available, " +
16809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                  "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
16819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                  " or by bluez.\n");
16829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
16839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
16849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // bluez API wants pin as a string
16859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String pinString;
16869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
16879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pinString = new String(pin, "UTF8");
16889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (UnsupportedEncodingException uee) {
16899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.e(TAG, "UTF8 not supported?!?");
16909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
16919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
16929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return setPinNative(address, pinString, data.intValue());
16939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
16949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1695b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    public synchronized boolean setPasskey(String address, int passkey) {
1696b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1697b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                                                "Need BLUETOOTH_ADMIN permission");
16988c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
16998c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1700005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (passkey < 0 || passkey > 999999 || !BluetoothAdapter.checkBluetoothAddress(address)) {
1701b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            return false;
1702b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        }
1703b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        address = address.toUpperCase();
1704b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
1705b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        if (data == null) {
1706b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            Log.w(TAG, "setPasskey(" + address + ") called but no native data available, " +
1707b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                  "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
1708b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                  " or by bluez.\n");
1709b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            return false;
1710b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        }
1711b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        return setPasskeyNative(address, passkey, data.intValue());
1712b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    }
1713b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh
1714b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    public synchronized boolean setPairingConfirmation(String address, boolean confirm) {
1715b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1716b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                                                "Need BLUETOOTH_ADMIN permission");
17178c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
17188c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1719b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        address = address.toUpperCase();
1720b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
1721b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        if (data == null) {
1722b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            Log.w(TAG, "setPasskey(" + address + ") called but no native data available, " +
1723b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                  "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
1724b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                  " or by bluez.\n");
1725b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            return false;
1726b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        }
1727b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        return setPairingConfirmationNative(address, confirm, data.intValue());
1728b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    }
1729b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh
1730b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    public synchronized boolean cancelPairingUserInput(String address) {
17319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
17329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
17338c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
17348c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1735005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
17369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
17379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1738005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        mBondState.setBondState(address, BluetoothDevice.BOND_NONE,
1739397d8f4f4829a45f4fe7a672cc395466bbc0f442Jaikumar Ganesh                BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
17409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        address = address.toUpperCase();
17419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
17429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (data == null) {
1743b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            Log.w(TAG, "cancelUserInputNative(" + address + ") called but no native data " +
1744b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                "available, ignoring. Maybe the PasskeyAgent Request was already cancelled " +
1745b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                "by the remote or by bluez.\n");
17469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
17479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1748b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        return cancelPairingUserInputNative(address, data.intValue());
17499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
17509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17518c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh    /*package*/ void updateDeviceServiceChannelCache(String address) {
175210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        ParcelUuid[] deviceUuids = getRemoteUuids(address);
175310eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        // We are storing the rfcomm channel numbers only for the uuids
175410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        // we are interested in.
175510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        int channel;
175616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        if (DBG) log("updateDeviceServiceChannelCache(" + address + ")");
175716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
175816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        ArrayList<ParcelUuid> applicationUuids = new ArrayList();
175916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
176016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        synchronized (this) {
176116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            for (RemoteService service : mUuidCallbackTracker.keySet()) {
176216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (service.address.equals(address)) {
176316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    applicationUuids.add(service.uuid);
176416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                }
176516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
176616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
176710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
176810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        Map <ParcelUuid, Integer> value = new HashMap<ParcelUuid, Integer>();
176916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
177016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        // Retrieve RFCOMM channel for default uuids
177116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        for (ParcelUuid uuid : RFCOMM_UUIDS) {
177210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            if (BluetoothUuid.isUuidPresent(deviceUuids, uuid)) {
177316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                channel = getDeviceServiceChannelNative(getObjectPathFromAddress(address),
177416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        uuid.toString(), 0x0004);
177516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (DBG) log("\tuuid(system): " + uuid + " " + channel);
177610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh                value.put(uuid, channel);
177710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            }
177810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        }
177916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        // Retrieve RFCOMM channel for application requested uuids
178016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        for (ParcelUuid uuid : applicationUuids) {
178116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (BluetoothUuid.isUuidPresent(deviceUuids, uuid)) {
178216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                channel = getDeviceServiceChannelNative(getObjectPathFromAddress(address),
178316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        uuid.toString(), 0x0004);
178416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (DBG) log("\tuuid(application): " + uuid + " " + channel);
178516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                value.put(uuid, channel);
178616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
178716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
178816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
178916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        synchronized (this) {
179016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            // Make application callbacks
179116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            for (Iterator<RemoteService> iter = mUuidCallbackTracker.keySet().iterator();
179216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    iter.hasNext();) {
179316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                RemoteService service = iter.next();
179416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (service.address.equals(address)) {
179516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    channel = -1;
179616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    if (value.get(service.uuid) != null) {
179716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        channel = value.get(service.uuid);
179816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    }
179916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    if (channel != -1) {
180016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        if (DBG) log("Making callback for " + service.uuid + " with result " +
180116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                                channel);
180216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        IBluetoothCallback callback = mUuidCallbackTracker.get(service);
180316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        if (callback != null) {
180416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                            try {
180516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                                callback.onRfcommChannelFound(channel);
180616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                            } catch (RemoteException e) {Log.e(TAG, "", e);}
180716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        }
180816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
180916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        iter.remove();
181016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    }
181116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                }
181216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
181316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
181416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            // Update cache
181516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            mDeviceServiceChannelCache.put(address, value);
181616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
181710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh    }
181810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
181924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    /**
182024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     * b is a handle to a Binder instance, so that this service can be notified
182124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     * for Applications that terminate unexpectedly, to clean there service
182224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     * records
182324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     */
182424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    public synchronized int addRfcommServiceRecord(String serviceName, ParcelUuid uuid,
182524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            int channel, IBinder b) {
18268c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
18278c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return -1;
18288c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
182924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (serviceName == null || uuid == null || channel < 1 ||
183024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                channel > BluetoothSocket.MAX_RFCOMM_CHANNEL) {
183124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            return -1;
183224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
183324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (BluetoothUuid.isUuidPresent(BluetoothUuid.RESERVED_UUIDS, uuid)) {
183424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            Log.w(TAG, "Attempted to register a reserved UUID: " + uuid);
183524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            return -1;
183624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
183724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        int handle = addRfcommServiceRecordNative(serviceName,
183824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                uuid.getUuid().getMostSignificantBits(), uuid.getUuid().getLeastSignificantBits(),
183924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                (short)channel);
184024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (DBG) log("new handle " + Integer.toHexString(handle));
184124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (handle == -1) {
184224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            return -1;
184324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
184424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
184524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        int pid = Binder.getCallingPid();
184624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        mServiceRecordToPid.put(new Integer(handle), new Integer(pid));
184724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        try {
184824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            b.linkToDeath(new Reaper(handle, pid), 0);
184924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        } catch (RemoteException e) {}
185024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        return handle;
185124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    }
185224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
185324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    public void removeServiceRecord(int handle) {
185424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
185524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                                                "Need BLUETOOTH permission");
185624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        checkAndRemoveRecord(handle, Binder.getCallingPid());
185724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    }
185824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
185924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private synchronized void checkAndRemoveRecord(int handle, int pid) {
186024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        Integer handleInt = new Integer(handle);
186124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        Integer owner = mServiceRecordToPid.get(handleInt);
186224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (owner != null && pid == owner.intValue()) {
186324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            if (DBG) log("Removing service record " + Integer.toHexString(handle) + " for pid " +
186424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                    pid);
186524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            mServiceRecordToPid.remove(handleInt);
186624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            removeServiceRecordNative(handle);
186724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
186824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    }
186924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
187024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private class Reaper implements IBinder.DeathRecipient {
187124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        int pid;
187224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        int handle;
187324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        Reaper(int handle, int pid) {
187424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            this.pid = pid;
187524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            this.handle = handle;
187624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
187724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        public void binderDied() {
187824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            synchronized (BluetoothService.this) {
187924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                if (DBG) log("Tracked app " + pid + " died");
188024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                checkAndRemoveRecord(handle, pid);
188124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            }
188224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
188324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    }
188424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
18859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
18869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
18879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onReceive(Context context, Intent intent) {
18886e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh            if (intent == null) return;
18896e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh
18909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String action = intent.getAction();
18919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
18929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ContentResolver resolver = context.getContentResolver();
18939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Query the airplane mode from Settings.System just to make sure that
18949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // some random app is not sending this intent and disabling bluetooth
18959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                boolean enabled = !isAirplaneModeOn();
18969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // If bluetooth is currently expected to be on, then enable or disable bluetooth
18979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (Settings.Secure.getInt(resolver, Settings.Secure.BLUETOOTH_ON, 0) > 0) {
18989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (enabled) {
1899105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                        enable(false);
19009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } else {
19019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        disable(false);
19029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
19039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
19046e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh            } else if (Intent.ACTION_DOCK_EVENT.equals(action)) {
19056e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                int state = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
19066e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                        Intent.EXTRA_DOCK_STATE_UNDOCKED);
19076e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                if (DBG) Log.v(TAG, "Received ACTION_DOCK_EVENT with State:" + state);
19086e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                if (state == Intent.EXTRA_DOCK_STATE_UNDOCKED) {
19096e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                    mDockAddress = null;
19106e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                    mDockPin = null;
19116e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                } else {
19126e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                    SharedPreferences.Editor editor =
19136e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                        mContext.getSharedPreferences(SHARED_PREFERENCES_NAME,
19146e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                                mContext.MODE_PRIVATE).edit();
19156e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                    editor.putBoolean(SHARED_PREFERENCE_DOCK_ADDRESS + mDockAddress, true);
19166e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                    editor.commit();
19176e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                }
19189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
19199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
19209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
19219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19226e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh    private void registerForAirplaneMode(IntentFilter filter) {
192344303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        final ContentResolver resolver = mContext.getContentResolver();
192444303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        final String airplaneModeRadios = Settings.System.getString(resolver,
19259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Settings.System.AIRPLANE_MODE_RADIOS);
192644303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        final String toggleableRadios = Settings.System.getString(resolver,
192744303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey                Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
192844303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey
192944303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        mIsAirplaneSensitive = airplaneModeRadios == null ? true :
193044303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey                airplaneModeRadios.contains(Settings.System.RADIO_BLUETOOTH);
193144303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        mIsAirplaneToggleable = toggleableRadios == null ? false :
193244303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey                toggleableRadios.contains(Settings.System.RADIO_BLUETOOTH);
193344303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey
19349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mIsAirplaneSensitive) {
19356e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh            filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
19369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
19379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
19389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* Returns true if airplane mode is currently on */
19409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final boolean isAirplaneModeOn() {
19419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return Settings.System.getInt(mContext.getContentResolver(),
19429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Settings.System.AIRPLANE_MODE_ON, 0) == 1;
19439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
19449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19451caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    /* Broadcast the Uuid intent */
19461caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    /*package*/ synchronized void sendUuidIntent(String address) {
19476179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh        ParcelUuid[] uuid = getUuidFromCache(address);
19486179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh        Intent intent = new Intent(BluetoothDevice.ACTION_UUID);
19492d3b98d868cda30535505b2a2fba47aa1c9c052bJaikumar Ganesh        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
19506179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh        intent.putExtra(BluetoothDevice.EXTRA_UUID, uuid);
19516179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh        mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
19521caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
19536179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh        if (mUuidIntentTracker.contains(address))
19541caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            mUuidIntentTracker.remove(address);
195516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
195616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    }
195716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
195816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    /*package*/ synchronized void makeServiceChannelCallbacks(String address) {
195916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        for (Iterator<RemoteService> iter = mUuidCallbackTracker.keySet().iterator();
196016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                iter.hasNext();) {
196116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            RemoteService service = iter.next();
196216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (service.address.equals(address)) {
196316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (DBG) log("Cleaning up failed UUID channel lookup: " + service.address +
196416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        " " + service.uuid);
196516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                IBluetoothCallback callback = mUuidCallbackTracker.get(service);
196616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (callback != null) {
196716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    try {
196816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        callback.onRfcommChannelFound(-1);
196916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    } catch (RemoteException e) {Log.e(TAG, "", e);}
197016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                }
197116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
197216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                iter.remove();
197316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
197416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
19751caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    }
19761caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
19779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
19789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1979105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        switch(mBluetoothState) {
1980de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_OFF:
198124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            pw.println("Bluetooth OFF\n");
1982105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return;
1983de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_TURNING_ON:
198424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            pw.println("Bluetooth TURNING ON\n");
1985105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return;
1986de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_TURNING_OFF:
198724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            pw.println("Bluetooth TURNING OFF\n");
1988105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return;
1989de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_ON:
199024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            pw.println("Bluetooth ON\n");
1991105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
1992105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
199324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("mIsAirplaneSensitive = " + mIsAirplaneSensitive);
199444303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        pw.println("mIsAirplaneToggleable = " + mIsAirplaneToggleable);
199524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
199624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("Local address = " + getAddress());
199724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("Local name = " + getName());
199824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("isDiscovering() = " + isDiscovering());
1999105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
2000105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        BluetoothHeadset headset = new BluetoothHeadset(mContext, null);
2001105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
2002105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        pw.println("\n--Known devices--");
2003bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        for (String address : mDeviceProperties.keySet()) {
20041eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly            int bondState = mBondState.getBondState(address);
2005105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            pw.printf("%s %10s (%d) %s\n", address,
20061eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly                       toBondStateString(bondState),
2007105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                       mBondState.getAttempt(address),
2008105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                       getRemoteName(address));
200924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
201024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            Map<ParcelUuid, Integer> uuidChannels = mDeviceServiceChannelCache.get(address);
201124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            if (uuidChannels == null) {
201224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                pw.println("\tuuids = null");
201324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            } else {
201424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                for (ParcelUuid uuid : uuidChannels.keySet()) {
201524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                    Integer channel = uuidChannels.get(uuid);
201624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                    if (channel == null) {
201724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                        pw.println("\t" + uuid);
201824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                    } else {
201924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                        pw.println("\t" + uuid + " RFCOMM channel = " + channel);
20201eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly                    }
20211eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly                }
20221eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly            }
202316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            for (RemoteService service : mUuidCallbackTracker.keySet()) {
202416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (service.address.equals(address)) {
202516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    pw.println("\tPENDING CALLBACK: " + service.uuid);
202616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                }
202716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
2028105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
2029105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
2030d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String value = getProperty("Devices");
20311eada0d3d655d6396bf862da954d254856a1bc03Nick Pelly        String[] devicesObjectPath = null;
2032d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (value != null) {
2033d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            devicesObjectPath = value.split(",");
2034d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
2035105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        pw.println("\n--ACL connected devices--");
203624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (devicesObjectPath != null) {
203724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            for (String device : devicesObjectPath) {
203824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                pw.println(getAddressFromObjectPath(device));
203924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            }
2040105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
2041105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
2042105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Rather not do this from here, but no-where else and I need this
2043105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // dump
2044105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        pw.println("\n--Headset Service--");
2045740e39be6af3e366a4b82c030b5ea67ab144b42aJaikumar Ganesh        switch (headset.getState(headset.getCurrentHeadset())) {
2046105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        case BluetoothHeadset.STATE_DISCONNECTED:
2047105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            pw.println("getState() = STATE_DISCONNECTED");
2048105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            break;
2049105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        case BluetoothHeadset.STATE_CONNECTING:
2050105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            pw.println("getState() = STATE_CONNECTING");
2051105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            break;
2052105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        case BluetoothHeadset.STATE_CONNECTED:
2053105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            pw.println("getState() = STATE_CONNECTED");
2054105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            break;
2055105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        case BluetoothHeadset.STATE_ERROR:
2056105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            pw.println("getState() = STATE_ERROR");
2057105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            break;
2058105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
20596c901db72dbaf57d8fdf26adae6721de14ecae22Nick Pelly
206024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("\ngetCurrentHeadset() = " + headset.getCurrentHeadset());
206124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("getBatteryUsageHint() = " + headset.getBatteryUsageHint());
2062105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        headset.close();
206324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("\n--Application Service Records--");
206424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        for (Integer handle : mServiceRecordToPid.keySet()) {
206524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            Integer pid = mServiceRecordToPid.get(handle);
206624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            pw.println("\tpid " + pid + " handle " + Integer.toHexString(handle));
206724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
20689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
20699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2070d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ static int bluezStringToScanMode(boolean pairable, boolean discoverable) {
2071d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (pairable && discoverable)
2072bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            return BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE;
2073d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        else if (pairable && !discoverable)
2074bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            return BluetoothAdapter.SCAN_MODE_CONNECTABLE;
2075d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        else
2076bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            return BluetoothAdapter.SCAN_MODE_NONE;
20779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
20789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* package */ static String scanModeToBluezString(int mode) {
20809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        switch (mode) {
2081bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        case BluetoothAdapter.SCAN_MODE_NONE:
20829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "off";
2083bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
20849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "connectable";
2085bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
20869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "discoverable";
20879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
20889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return null;
20899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
20909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2091d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /*package*/ String getAddressFromObjectPath(String objectPath) {
2092b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh        String adapterObjectPath = getPropertyInternal("ObjectPath");
2093d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (adapterObjectPath == null || objectPath == null) {
2094d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            Log.e(TAG, "getAddressFromObjectPath: AdpaterObjectPath:" + adapterObjectPath +
2095d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                    "  or deviceObjectPath:" + objectPath + " is null");
2096d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return null;
2097d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
2098d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (!objectPath.startsWith(adapterObjectPath)) {
2099d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            Log.e(TAG, "getAddressFromObjectPath: AdpaterObjectPath:" + adapterObjectPath +
2100d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                    "  is not a prefix of deviceObjectPath:" + objectPath +
2101d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                    "bluetoothd crashed ?");
2102d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return null;
2103d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
2104d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String address = objectPath.substring(adapterObjectPath.length());
2105d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (address != null) return address.replace('_', ':');
2106d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
2107d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        Log.e(TAG, "getAddressFromObjectPath: Address being returned is null");
2108d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return null;
2109d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
2110d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
2111d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /*package*/ String getObjectPathFromAddress(String address) {
2112b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh        String path = getPropertyInternal("ObjectPath");
2113d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (path == null) {
2114d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            Log.e(TAG, "Error: Object Path is null");
2115d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return null;
2116d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
2117d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        path = path + address.replace(":", "_");
2118d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return path;
2119d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
2120d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
2121b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh    /*package */ void setLinkTimeout(String address, int num_slots) {
2122b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh        String path = getObjectPathFromAddress(address);
2123b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh        boolean result = setLinkTimeoutNative(path, num_slots);
2124b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh
2125b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh        if (!result) log("Set Link Timeout to:" + num_slots + " slots failed");
2126b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh    }
2127b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh
21289b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public boolean connectHeadset(String address) {
2129f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
21309b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (state != null) {
2131f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            Message msg = new Message();
2132f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.arg1 = BluetoothDeviceProfileState.CONNECT_HFP_OUTGOING;
2133f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.obj = state;
2134f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            mHfpProfileState.sendMessage(msg);
2135f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            return true;
21369b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
21379b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        return false;
21389b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
21399b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
21409b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public boolean disconnectHeadset(String address) {
2141f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
21429b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (state != null) {
2143f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            Message msg = new Message();
2144f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.arg1 = BluetoothDeviceProfileState.DISCONNECT_HFP_OUTGOING;
2145f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.obj = state;
2146f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            mHfpProfileState.sendMessage(msg);
21479b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            return true;
21489b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
21499b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        return false;
21509b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
21519b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
21529b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public boolean connectSink(String address) {
2153f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
21549b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (state != null) {
2155f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            Message msg = new Message();
2156f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.arg1 = BluetoothDeviceProfileState.CONNECT_A2DP_OUTGOING;
2157f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.obj = state;
2158f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            mA2dpProfileState.sendMessage(msg);
2159f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            return true;
21609b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
21619b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        return false;
21629b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
21639b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
21649b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public boolean disconnectSink(String address) {
2165f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
21669b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (state != null) {
2167f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            Message msg = new Message();
2168f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.arg1 = BluetoothDeviceProfileState.DISCONNECT_A2DP_OUTGOING;
2169f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.obj = state;
2170f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            mA2dpProfileState.sendMessage(msg);
21719b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            return true;
21729b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
21739b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        return false;
21749b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
21759b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
2176f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh    private BluetoothDeviceProfileState addProfileState(String address) {
2177f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
21789b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (state != null) return state;
21799b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
2180f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        state = new BluetoothDeviceProfileState(mContext, address, this, mA2dpService);
2181f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        mDeviceProfileState.put(address, state);
21829b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        state.start();
21839b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        return state;
21849b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
21859b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
21869b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    private void removeProfileState(String address) {
2187f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        mDeviceProfileState.remove(address);
21889b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
21899b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
21909b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    private void initProfileState() {
21919b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        String []bonds = null;
21929b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        String val = getPropertyInternal("Devices");
21939b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (val != null) {
21949b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            bonds = val.split(",");
21959b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
21969b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (bonds == null) {
21979b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            return;
21989b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
21999b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
22009b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        for (String path : bonds) {
22019b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            String address = getAddressFromObjectPath(path);
2202f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            BluetoothDeviceProfileState state = addProfileState(address);
22039b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            // Allow 8 secs for SDP records to get registered.
22049b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            Message msg = new Message();
2205f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.what = BluetoothDeviceProfileState.AUTO_CONNECT_PROFILES;
22069b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            state.sendMessageDelayed(msg, 8000);
22079b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
22089b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
22099b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
22109b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public boolean notifyIncomingConnection(String address) {
2211f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        BluetoothDeviceProfileState state =
2212f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh             mDeviceProfileState.get(address);
22139b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (state != null) {
22149b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            Message msg = new Message();
2215f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.what = BluetoothDeviceProfileState.CONNECT_HFP_INCOMING;
22169b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            state.sendMessage(msg);
22179b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            return true;
22189b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
22199b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        return false;
22209b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
22219b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
22229b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    /*package*/ boolean notifyIncomingA2dpConnection(String address) {
2223f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh       BluetoothDeviceProfileState state =
2224f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            mDeviceProfileState.get(address);
22259b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh       if (state != null) {
22269b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh           Message msg = new Message();
2227f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh           msg.what = BluetoothDeviceProfileState.CONNECT_A2DP_INCOMING;
22289b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh           state.sendMessage(msg);
22299b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh           return true;
22309b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh       }
22319b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh       return false;
22329b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
22339b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
22349b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    /*package*/ void setA2dpService(BluetoothA2dpService a2dpService) {
22359b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        mA2dpService = a2dpService;
22369b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
22379b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
22389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static void log(String msg) {
22399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Log.d(TAG, msg);
22409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2241d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
2242d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native static void classInitNative();
2243d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native void initializeNativeDataNative();
2244d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setupNativeDataNative();
2245d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean tearDownNativeDataNative();
2246d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native void cleanupNativeDataNative();
2247d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native String getAdapterPathNative();
2248d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
2249d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native int isEnabledNative();
2250d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native int enableNative();
2251d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native int disableNative();
2252d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
2253d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native Object[] getAdapterPropertiesNative();
2254d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native Object[] getDevicePropertiesNative(String objectPath);
2255d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setAdapterPropertyStringNative(String key, String value);
2256d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setAdapterPropertyIntegerNative(String key, int value);
2257d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setAdapterPropertyBooleanNative(String key, int value);
2258d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
2259d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean startDiscoveryNative();
2260d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean stopDiscoveryNative();
2261d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
2262d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean createPairedDeviceNative(String address, int timeout_ms);
2263d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean cancelDeviceCreationNative(String address);
2264d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean removeDeviceNative(String objectPath);
2265d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native int getDeviceServiceChannelNative(String objectPath, String uuid,
2266d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            int attributeId);
2267d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
2268b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    private native boolean cancelPairingUserInputNative(String address, int nativeData);
2269d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setPinNative(String address, String pin, int nativeData);
2270b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    private native boolean setPasskeyNative(String address, int passkey, int nativeData);
2271b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    private native boolean setPairingConfirmationNative(String address, boolean confirm,
2272b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            int nativeData);
227324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private native boolean setDevicePropertyBooleanNative(String objectPath, String key,
227424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            int value);
22751caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    private native boolean createDeviceNative(String address);
227616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    /*package*/ native boolean discoverServicesNative(String objectPath, String pattern);
227710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
227824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private native int addRfcommServiceRecordNative(String name, long uuidMsb, long uuidLsb,
227924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            short channel);
228024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private native boolean removeServiceRecordNative(int handle);
2281b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh    private native boolean setLinkTimeoutNative(String path, int num_slots);
2282545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh    private native boolean connectInputDeviceNative(String path);
2283545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh    private native boolean disconnectInputDeviceNative(String path);
22849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
2285