19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * TODO: Move this to
19bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly * java/services/com/android/server/BluetoothService.java
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * and make the contructor package private again.
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @hide
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.server;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
27bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pellyimport android.bluetooth.BluetoothAdapter;
28dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganeshimport android.bluetooth.BluetoothClass;
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.bluetooth.BluetoothDevice;
30f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganeshimport android.bluetooth.BluetoothDeviceProfileState;
315a1e4cf83f5be1b5d79e2643fa791aa269b6a4bcJaikumar Ganeshimport android.bluetooth.BluetoothHeadset;
322ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganeshimport android.bluetooth.BluetoothHealthAppConfiguration;
334ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganeshimport android.bluetooth.BluetoothInputDevice;
346fdd0c6274c81b337ad35b70480f881daf7354c3Danica Changimport android.bluetooth.BluetoothPan;
3596a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganeshimport android.bluetooth.BluetoothProfile;
36f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganeshimport android.bluetooth.BluetoothProfileState;
3724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pellyimport android.bluetooth.BluetoothSocket;
3810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganeshimport android.bluetooth.BluetoothUuid;
39bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pellyimport android.bluetooth.IBluetooth;
4016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pellyimport android.bluetooth.IBluetoothCallback;
41fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganeshimport android.bluetooth.IBluetoothHealthCallback;
42ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganeshimport android.bluetooth.IBluetoothStateChangeCallback;
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.BroadcastReceiver;
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ContentResolver;
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Intent;
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.IntentFilter;
486e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganeshimport android.content.SharedPreferences;
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Binder;
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Handler;
513fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport android.os.IBinder;
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Message;
532ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganeshimport android.os.ParcelFileDescriptor;
543fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport android.os.ParcelUuid;
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.RemoteException;
56105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Projectimport android.os.ServiceManager;
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.Settings;
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log;
59cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganeshimport android.util.Pair;
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
61fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganeshimport com.android.internal.app.IBatteryStats;
62fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh
633fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.BufferedInputStream;
64a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xieimport java.io.BufferedReader;
653fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.BufferedWriter;
66a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xieimport java.io.DataInputStream;
67a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xieimport java.io.File;
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileDescriptor;
693fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.FileInputStream;
703fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.FileNotFoundException;
713fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.FileWriter;
723fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganeshimport java.io.IOException;
73ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganeshimport java.io.InputStreamReader;
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.PrintWriter;
75a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xieimport java.io.RandomAccessFile;
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.UnsupportedEncodingException;
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList;
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Arrays;
79ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganeshimport java.util.Collection;
80ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganeshimport java.util.Collections;
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.HashMap;
8216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pellyimport java.util.Iterator;
835a1e4cf83f5be1b5d79e2643fa791aa269b6a4bcJaikumar Ganeshimport java.util.List;
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Map;
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
86bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pellypublic class BluetoothService extends IBluetooth.Stub {
87bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    private static final String TAG = "BluetoothService";
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final boolean DBG = true;
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mNativeData;
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private BluetoothEventLoop mEventLoop;
9298f06da8ed2851a768358de1979838ad1bb6d187Matthew Xie    private BluetoothHeadset mHeadsetProxy;
934ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh    private BluetoothInputDevice mInputDevice;
9474ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh    private BluetoothPan mPan;
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mIsAirplaneSensitive;
9644303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey    private boolean mIsAirplaneToggleable;
977f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    private BluetoothAdapterStateMachine mBluetoothState;
9884690c88f37f395094147d27ace8319a2803a522Jaikumar Ganesh    private int[] mAdapterSdpHandles;
9950b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh    private ParcelUuid[] mAdapterUuids;
100997c7612a8cf63748165144b423ff2ae8e73c3e9Nick Pelly
101bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    private BluetoothAdapter mAdapter;  // constant after init()
1029a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    private final BluetoothBondState mBondState;  // local cache of bondings
103105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private final IBatteryStats mBatteryStats;
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final Context mContext;
105ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh    private Map<Integer, IBluetoothStateChangeCallback> mStateChangeTracker =
106ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh        Collections.synchronizedMap(new HashMap<Integer, IBluetoothStateChangeCallback>());
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
109a8571f15c39da2b7c6e672fef26106f5ac60dea0Jaikumar Ganesh    static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1113fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    private static final String DOCK_ADDRESS_PATH = "/sys/class/switch/dock/bt_addr";
1123fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    private static final String DOCK_PIN_PATH = "/sys/class/switch/dock/bt_pin";
1133fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
1146e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh    private static final String SHARED_PREFERENCE_DOCK_ADDRESS = "dock_bluetooth_address";
1156e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh    private static final String SHARED_PREFERENCES_NAME = "bluetooth_service_settings";
1166e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh
1177f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    private static final int MESSAGE_UUID_INTENT = 1;
1187f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    private static final int MESSAGE_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 2;
119484867a8ed3d46fbb8df493c77f2e2d46a0db654Matthew Xie    private static final int MESSAGE_REMOVE_SERVICE_RECORD = 3;
120a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh
121ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh    private static final int RFCOMM_RECORD_REAPER = 10;
122ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh    private static final int STATE_CHANGE_REAPER = 11;
123ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh
124a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    // The time (in millisecs) to delay the pairing attempt after the first
125a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    // auto pairing attempt fails. We use an exponential delay with
126a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    // INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY as the initial value and
127a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    // MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY as the max value.
128a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    private static final long INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 3000;
129a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    private static final long MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 12000;
1301caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
1311caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    // The timeout used to sent the UUIDs Intent
1321caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    // This timeout should be greater than the page timeout
1331caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    private static final int UUID_INTENT_DELAY = 6000;
134105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
13516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    /** Always retrieve RFCOMM channel for these SDP UUIDs */
13616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private static final ParcelUuid[] RFCOMM_UUIDS = {
13716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            BluetoothUuid.Handsfree,
13816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            BluetoothUuid.HSP,
13916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            BluetoothUuid.ObexObjectPush };
14016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
1419a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    private final BluetoothAdapterProperties mAdapterProperties;
1429a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    private final BluetoothDeviceProperties mDeviceProperties;
143d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
14416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private final HashMap<String, Map<ParcelUuid, Integer>> mDeviceServiceChannelCache;
14516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private final ArrayList<String> mUuidIntentTracker;
14616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private final HashMap<RemoteService, IBluetoothCallback> mUuidCallbackTracker;
1471caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
148c980a495a6d357219a9e0860129ae6bb6d541843Jason Simmons    private static class ServiceRecordClient {
149c980a495a6d357219a9e0860129ae6bb6d541843Jason Simmons        int pid;
150c980a495a6d357219a9e0860129ae6bb6d541843Jason Simmons        IBinder binder;
151c980a495a6d357219a9e0860129ae6bb6d541843Jason Simmons        IBinder.DeathRecipient death;
152c980a495a6d357219a9e0860129ae6bb6d541843Jason Simmons    }
153c980a495a6d357219a9e0860129ae6bb6d541843Jason Simmons    private final HashMap<Integer, ServiceRecordClient> mServiceRecordToPid;
15424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
155f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh    private final HashMap<String, BluetoothDeviceProfileState> mDeviceProfileState;
156f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh    private final BluetoothProfileState mA2dpProfileState;
157f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh    private final BluetoothProfileState mHfpProfileState;
1589b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
1599b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    private BluetoothA2dpService mA2dpService;
160cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    private final HashMap<String, Pair<byte[], byte[]>> mDeviceOobData;
161545e6708adda6859932b55fd824794b1401f5318Jaikumar Ganesh
162a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh    private int mProfilesConnected = 0, mProfilesConnecting = 0, mProfilesDisconnecting = 0;
163707952ecd4b6cae25aabcf51f94d702a65847e9eJaikumar Ganesh
1643fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    private static String mDockAddress;
1653fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    private String mDockPin;
1663fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
167c53cab20b225ba69057441ecb06db6478ab8ff9bJaikumar Ganesh    private int mAdapterConnectionState = BluetoothAdapter.STATE_DISCONNECTED;
168a8571f15c39da2b7c6e672fef26106f5ac60dea0Jaikumar Ganesh    private BluetoothPanProfileHandler mBluetoothPanProfileHandler;
16930b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    private BluetoothInputProfileHandler mBluetoothInputProfileHandler;
1702ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    private BluetoothHealthProfileHandler mBluetoothHealthProfileHandler;
171a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    private static final String INCOMING_CONNECTION_FILE =
172a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie      "/data/misc/bluetooth/incoming_connection.conf";
173a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    private HashMap<String, Pair<Integer, String>> mIncomingConnections;
174cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh    private HashMap<Integer, Pair<Integer, Integer>> mProfileConnectionState;
175c53cab20b225ba69057441ecb06db6478ab8ff9bJaikumar Ganesh
17616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    private static class RemoteService {
17716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        public String address;
17816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        public ParcelUuid uuid;
17916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        public RemoteService(String address, ParcelUuid uuid) {
18016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            this.address = address;
18116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            this.uuid = uuid;
18216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
18316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        @Override
18416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        public boolean equals(Object o) {
18516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (o instanceof RemoteService) {
18616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                RemoteService service = (RemoteService)o;
18716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                return address.equals(service.address) && uuid.equals(service.uuid);
18816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
18916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            return false;
19016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
1915f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root
1925f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root        @Override
1935f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root        public int hashCode() {
1945f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root            int hash = 1;
1955f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root            hash = hash * 31 + (address == null ? 0 : address.hashCode());
1965f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root            hash = hash * 31 + (uuid == null ? 0 : uuid.hashCode());
1975f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root            return hash;
1985f61416305c47c4db0b94c0cf500e9a9d11d4cdbKenny Root        }
19916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    }
20016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static {
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        classInitNative();
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
205bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    public BluetoothService(Context context) {
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext = context;
207105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
208105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Need to do this in place of:
209105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // mBatteryStats = BatteryStatsService.getService();
210105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Since we can not import BatteryStatsService from here. This class really needs to be
211105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // moved to java/services/com/android/server/
212105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo"));
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        initializeNativeDataNative();
215ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project
216ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project        if (isEnabledNative() == 1) {
217ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project            Log.w(TAG, "Bluetooth daemons already running - runtime restart? ");
218ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project            disableNative();
2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
220ba87e3e6c985e7175152993b5efcc7dd2f0e1c93The Android Open Source Project
2219a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        mBondState = new BluetoothBondState(context, this);
2229a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        mAdapterProperties = new BluetoothAdapterProperties(context, this);
2239a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        mDeviceProperties = new BluetoothDeviceProperties(this);
22410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
22510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        mDeviceServiceChannelCache = new HashMap<String, Map<ParcelUuid, Integer>>();
226cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        mDeviceOobData = new HashMap<String, Pair<byte[], byte[]>>();
2271caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        mUuidIntentTracker = new ArrayList<String>();
22816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        mUuidCallbackTracker = new HashMap<RemoteService, IBluetoothCallback>();
229c980a495a6d357219a9e0860129ae6bb6d541843Jason Simmons        mServiceRecordToPid = new HashMap<Integer, ServiceRecordClient>();
230f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        mDeviceProfileState = new HashMap<String, BluetoothDeviceProfileState>();
231f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        mA2dpProfileState = new BluetoothProfileState(mContext, BluetoothProfileState.A2DP);
232f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        mHfpProfileState = new BluetoothProfileState(mContext, BluetoothProfileState.HFP);
233f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh
234f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        mHfpProfileState.start();
235f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        mA2dpProfileState.start();
2363fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
2373fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        IntentFilter filter = new IntentFilter();
2386e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh        registerForAirplaneMode(filter);
2396e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh
2403fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        filter.addAction(Intent.ACTION_DOCK_EVENT);
2416e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh        mContext.registerReceiver(mReceiver, filter);
24230b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        mBluetoothInputProfileHandler = BluetoothInputProfileHandler.getInstance(mContext, this);
243a8571f15c39da2b7c6e672fef26106f5ac60dea0Jaikumar Ganesh        mBluetoothPanProfileHandler = BluetoothPanProfileHandler.getInstance(mContext, this);
2442ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        mBluetoothHealthProfileHandler = BluetoothHealthProfileHandler.getInstance(mContext, this);
245a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        mIncomingConnections = new HashMap<String, Pair<Integer, String>>();
246cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh        mProfileConnectionState = new HashMap<Integer, Pair<Integer, Integer>>();
2473fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    }
2483fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
2499b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public static synchronized String readDockBluetoothAddress() {
2503fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        if (mDockAddress != null) return mDockAddress;
2513fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
2523fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        BufferedInputStream file = null;
2533fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        String dockAddress;
2543fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        try {
2553fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            file = new BufferedInputStream(new FileInputStream(DOCK_ADDRESS_PATH));
2563fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            byte[] address = new byte[17];
2573fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            file.read(address);
2583fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            dockAddress = new String(address);
2593fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            dockAddress = dockAddress.toUpperCase();
2603fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            if (BluetoothAdapter.checkBluetoothAddress(dockAddress)) {
2613fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                mDockAddress = dockAddress;
2623fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                return mDockAddress;
2633fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            } else {
2649a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                Log.e(TAG, "CheckBluetoothAddress failed for car dock address: "
2659a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                        + dockAddress);
2663fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            }
2673fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        } catch (FileNotFoundException e) {
2689a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            Log.e(TAG, "FileNotFoundException while trying to read dock address");
2693fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        } catch (IOException e) {
2709a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            Log.e(TAG, "IOException while trying to read dock address");
2713fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        } finally {
2723fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            if (file != null) {
2733fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                try {
2743fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                    file.close();
2753fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                } catch (IOException e) {
2763fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                    // Ignore
2773fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                }
2783fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            }
2793fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        }
2803fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        mDockAddress = null;
2813fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        return null;
2823fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    }
2833fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
2843fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    private synchronized boolean writeDockPin() {
2853fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        BufferedWriter out = null;
2863fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        try {
2873fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            out = new BufferedWriter(new FileWriter(DOCK_PIN_PATH));
2883fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
2893fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            // Generate a random 4 digit pin between 0000 and 9999
2903fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            // This is not truly random but good enough for our purposes.
2913fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            int pin = (int) Math.floor(Math.random() * 10000);
2923fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
2933fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            mDockPin = String.format("%04d", pin);
2943fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            out.write(mDockPin);
2953fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            return true;
2963fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        } catch (FileNotFoundException e) {
2979a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            Log.e(TAG, "FileNotFoundException while trying to write dock pairing pin");
2983fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        } catch (IOException e) {
2999a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            Log.e(TAG, "IOException while while trying to write dock pairing pin");
3003fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        } finally {
3013fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            if (out != null) {
3023fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                try {
3033fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                    out.close();
3043fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                } catch (IOException e) {
3053fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                    // Ignore
3063fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                }
3073fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            }
3083fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        }
3093fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        mDockPin = null;
3103fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        return false;
3113fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    }
3123fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
3133fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    /*package*/ synchronized String getDockPin() {
3143fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        return mDockPin;
315bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    }
316bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly
317bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly    public synchronized void initAfterRegistration() {
318f242b7b931898856bcbcb7ec36cacf43098ba544Nick Pelly        mAdapter = BluetoothAdapter.getDefaultAdapter();
3197f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        mBluetoothState = new BluetoothAdapterStateMachine(mContext, this, mAdapter);
3207f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        mBluetoothState.start();
3219de1feb673499519cb380a142ba1e453109480bdMatthew Xie        if (mContext.getResources().getBoolean
3229de1feb673499519cb380a142ba1e453109480bdMatthew Xie            (com.android.internal.R.bool.config_bluetooth_adapter_quick_switch)) {
3239de1feb673499519cb380a142ba1e453109480bdMatthew Xie            mBluetoothState.sendMessage(BluetoothAdapterStateMachine.TURN_HOT);
3249de1feb673499519cb380a142ba1e453109480bdMatthew Xie        }
3257f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        mEventLoop = mBluetoothState.getBluetoothEventLoop();
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3287d0548d0944e48421857de4aec2822ced325bea0Jaikumar Ganesh    public synchronized void initAfterA2dpRegistration() {
3297d0548d0944e48421857de4aec2822ced325bea0Jaikumar Ganesh        mEventLoop.getProfileProxy();
3307d0548d0944e48421857de4aec2822ced325bea0Jaikumar Ganesh    }
3317d0548d0944e48421857de4aec2822ced325bea0Jaikumar Ganesh
3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void finalize() throws Throwable {
3346e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh        mContext.unregisterReceiver(mReceiver);
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            cleanupNativeDataNative();
3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super.finalize();
3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean isEnabled() {
3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
3448c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        return isEnabledInternal();
3458c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh    }
3468c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
3478c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh    private boolean isEnabledInternal() {
3487f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        return (getBluetoothStateInternal() == BluetoothAdapter.STATE_ON);
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
351105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    public int getBluetoothState() {
352105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
3537f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        return getBluetoothStateInternal();
354105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    }
355105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
3569a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    int getBluetoothStateInternal() {
3577f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        return mBluetoothState.getBluetoothAdapterState();
3589a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    }
359105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Bring down bluetooth and disable BT in settings. Returns true on success.
3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean disable() {
3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return disable(true);
3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Bring down bluetooth. Returns true on success.
3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
370e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly     * @param saveSetting If true, persist the new setting
3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean disable(boolean saveSetting) {
373e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission");
3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3757f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        int adapterState = getBluetoothStateInternal();
3767f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie
3777f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        switch (adapterState) {
378de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_OFF:
379105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return true;
380de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.STATE_ON:
381105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            break;
382105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        default:
383105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return false;
384105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
3857a0f816916abb200d9337a5afde5d6d2a637a20aJaikumar Ganesh
3867f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        mBluetoothState.sendMessage(BluetoothAdapterStateMachine.USER_TURN_OFF, saveSetting);
387105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        return true;
388105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    }
389105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
3907f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    synchronized void disconnectDevices() {
3917a0f816916abb200d9337a5afde5d6d2a637a20aJaikumar Ganesh        // Disconnect devices handled by BluetoothService.
3927a0f816916abb200d9337a5afde5d6d2a637a20aJaikumar Ganesh        for (BluetoothDevice device: getConnectedInputDevices()) {
3937a0f816916abb200d9337a5afde5d6d2a637a20aJaikumar Ganesh            disconnectInputDevice(device);
3947a0f816916abb200d9337a5afde5d6d2a637a20aJaikumar Ganesh        }
3957a0f816916abb200d9337a5afde5d6d2a637a20aJaikumar Ganesh
3967a0f816916abb200d9337a5afde5d6d2a637a20aJaikumar Ganesh        for (BluetoothDevice device: getConnectedPanDevices()) {
3977a0f816916abb200d9337a5afde5d6d2a637a20aJaikumar Ganesh            disconnectPanDevice(device);
3987a0f816916abb200d9337a5afde5d6d2a637a20aJaikumar Ganesh        }
3997a0f816916abb200d9337a5afde5d6d2a637a20aJaikumar Ganesh    }
400105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
4017f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    /**
402dcbc97fc28f4eb5910acc11dfac5efcd597c737dMatthew Xie     * The Bluetooth has been turned off, but hot. Do bonding, profile cleanup
4037f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie     */
4047f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    synchronized void finishDisable() {
4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // mark in progress bondings as cancelled
4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (String address : mBondState.listInState(BluetoothDevice.BOND_BONDING)) {
407005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            mBondState.setBondState(address, BluetoothDevice.BOND_NONE,
4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4112d1fc4e3f5eb612f9ef8a50080310ced1dfaaadfJaikumar Ganesh        // Stop the profile state machine for bonded devices.
4122d1fc4e3f5eb612f9ef8a50080310ced1dfaaadfJaikumar Ganesh        for (String address : mBondState.listInState(BluetoothDevice.BOND_BONDED)) {
4132d1fc4e3f5eb612f9ef8a50080310ced1dfaaadfJaikumar Ganesh            removeProfileState(address);
4142d1fc4e3f5eb612f9ef8a50080310ced1dfaaadfJaikumar Ganesh        }
4152d1fc4e3f5eb612f9ef8a50080310ced1dfaaadfJaikumar Ganesh
4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // update mode
417de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        Intent intent = new Intent(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
418de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        intent.putExtra(BluetoothAdapter.EXTRA_SCAN_MODE, BluetoothAdapter.SCAN_MODE_NONE);
4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.sendBroadcast(intent, BLUETOOTH_PERM);
420dcbc97fc28f4eb5910acc11dfac5efcd597c737dMatthew Xie    }
4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
422dcbc97fc28f4eb5910acc11dfac5efcd597c737dMatthew Xie    /**
423dcbc97fc28f4eb5910acc11dfac5efcd597c737dMatthew Xie     * Local clean up after broadcasting STATE_OFF intent
424dcbc97fc28f4eb5910acc11dfac5efcd597c737dMatthew Xie     */
425dcbc97fc28f4eb5910acc11dfac5efcd597c737dMatthew Xie    synchronized void cleanupAfterFinishDisable() {
426bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        mAdapterProperties.clear();
427dcbc97fc28f4eb5910acc11dfac5efcd597c737dMatthew Xie
428dcbc97fc28f4eb5910acc11dfac5efcd597c737dMatthew Xie        for (Integer srHandle : mServiceRecordToPid.keySet()) {
429dcbc97fc28f4eb5910acc11dfac5efcd597c737dMatthew Xie            removeServiceRecordNative(srHandle);
430dcbc97fc28f4eb5910acc11dfac5efcd597c737dMatthew Xie        }
43124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        mServiceRecordToPid.clear();
432105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
433a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh        mProfilesConnected = 0;
434a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh        mProfilesConnecting = 0;
435a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh        mProfilesDisconnecting = 0;
436c53cab20b225ba69057441ecb06db6478ab8ff9bJaikumar Ganesh        mAdapterConnectionState = BluetoothAdapter.STATE_DISCONNECTED;
43750b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        mAdapterUuids = null;
43850b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        mAdapterSdpHandles = null;
439a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh
440105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        // Log bluetooth off to battery stats.
441105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        long ident = Binder.clearCallingIdentity();
442105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        try {
443105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            mBatteryStats.noteBluetoothOff();
444105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        } catch (RemoteException e) {
445105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        } finally {
446105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            Binder.restoreCallingIdentity(ident);
447105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4507f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    /**
4517f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie     * power off Bluetooth
4527f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie     */
4537f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    synchronized void shutoffBluetooth() {
45414e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie        if (mAdapterSdpHandles != null) removeReservedServiceRecordsNative(mAdapterSdpHandles);
45514e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie        setBluetoothTetheringNative(false, BluetoothPanProfileHandler.NAP_ROLE,
45614e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie                BluetoothPanProfileHandler.NAP_BRIDGE);
4577f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        tearDownNativeDataNative();
45814e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie    }
45914e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie
46014e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie    /**
46114e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie     * Data clean up after Bluetooth shutoff
46214e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie     */
46314e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie    synchronized void cleanNativeAfterShutoffBluetooth() {
46414e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie        // Ths method is called after shutdown of event loop in the Bluetooth shut down
46514e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie        // procedure
46614e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie
46714e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie        // the adapter property could be changed before event loop is stoped, clear it again
46814e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie        mAdapterProperties.clear();
4697f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        disableNative();
4707f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    }
4717f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie
472105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    /** Bring up BT and persist BT on in settings */
473105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    public boolean enable() {
474105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        return enable(true);
4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Enable this Bluetooth device, asynchronously.
4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * This turns on/off the underlying hardware.
4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
481105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project     * @param saveSetting If true, persist the new state of BT in settings
482105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project     * @return True on success (so far)
4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
484105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    public synchronized boolean enable(boolean saveSetting) {
4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Airplane mode can prevent Bluetooth radio from being turned on.
48944303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        if (mIsAirplaneSensitive && isAirplaneModeOn() && !mIsAirplaneToggleable) {
4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4927f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        mBluetoothState.sendMessage(BluetoothAdapterStateMachine.USER_TURN_ON, saveSetting);
4937f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        return true;
4947f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    }
4957f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie
4967f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    /**
4977f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie     * Turn on Bluetooth Module, Load firmware, and do all the preparation
4987f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie     * needed to get the Bluetooth Module ready but keep it not discoverable
4997f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie     * and not connectable.
5007f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie     */
5017f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    /* package */ synchronized boolean prepareBluetooth() {
5027f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        if (!setupNativeDataNative()) {
5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5057f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        switchConnectable(false);
5067f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        updateSdpRecords();
5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final Handler mHandler = new Handler() {
5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void handleMessage(Message msg) {
5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            switch (msg.what) {
5141caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            case MESSAGE_UUID_INTENT:
5151caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh                String address = (String)msg.obj;
51616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (address != null) {
5171caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh                    sendUuidIntent(address);
51816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    makeServiceChannelCallbacks(address);
51916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                }
5201caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh                break;
521a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            case MESSAGE_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY:
522a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                address = (String)msg.obj;
5238adcacbf83697d1299812f5365380b097898567aJaikumar Ganesh                if (address == null) return;
5248adcacbf83697d1299812f5365380b097898567aJaikumar Ganesh                int attempt = mBondState.getAttempt(address);
5258adcacbf83697d1299812f5365380b097898567aJaikumar Ganesh
5268adcacbf83697d1299812f5365380b097898567aJaikumar Ganesh                // Try only if attemps are in progress and cap it 2 attempts
5278adcacbf83697d1299812f5365380b097898567aJaikumar Ganesh                // The 2 attempts cap is a fail safe if the stack returns
5288adcacbf83697d1299812f5365380b097898567aJaikumar Ganesh                // an incorrect error code for bonding failures and if the pin
5298adcacbf83697d1299812f5365380b097898567aJaikumar Ganesh                // is entered wrongly twice we should abort.
5308adcacbf83697d1299812f5365380b097898567aJaikumar Ganesh                if (attempt > 0 && attempt <= 2) {
5318adcacbf83697d1299812f5365380b097898567aJaikumar Ganesh                    mBondState.attempt(address);
532a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                    createBond(address);
533a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                    return;
534a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                }
5358adcacbf83697d1299812f5365380b097898567aJaikumar Ganesh                if (attempt > 0) mBondState.clearPinAttempts(address);
536a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                break;
537484867a8ed3d46fbb8df493c77f2e2d46a0db654Matthew Xie            case MESSAGE_REMOVE_SERVICE_RECORD:
538484867a8ed3d46fbb8df493c77f2e2d46a0db654Matthew Xie                Pair<Integer, Integer> pair = (Pair<Integer, Integer>) msg.obj;
539484867a8ed3d46fbb8df493c77f2e2d46a0db654Matthew Xie                checkAndRemoveRecord(pair.first, pair.second);
540484867a8ed3d46fbb8df493c77f2e2d46a0db654Matthew Xie                break;
5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
54550b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh    private synchronized void addReservedSdpRecords(final ArrayList<ParcelUuid> uuids) {
54650b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        //Register SDP records.
54750b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        int[] svcIdentifiers = new int[uuids.size()];
54850b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        for (int i = 0; i < uuids.size(); i++) {
54950b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh            svcIdentifiers[i] = BluetoothUuid.getServiceIdentifierFromParcelUuid(uuids.get(i));
55050b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        }
55150b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        mAdapterSdpHandles = addReservedServiceRecordsNative(svcIdentifiers);
55250b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh    }
553105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
55450b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh    private synchronized void updateSdpRecords() {
55550b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        ArrayList<ParcelUuid> uuids = new ArrayList<ParcelUuid>();
55650b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh
55750b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        // Add the default records
55850b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        uuids.add(BluetoothUuid.HSP_AG);
55950b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        uuids.add(BluetoothUuid.ObexObjectPush);
56050b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh
56150b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        if (mContext.getResources().
56250b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh                getBoolean(com.android.internal.R.bool.config_voice_capable)) {
56350b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh            uuids.add(BluetoothUuid.Handsfree_AG);
56450b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh            uuids.add(BluetoothUuid.PBAP_PSE);
56550b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        }
56650b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh
56750b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        // Add SDP records for profiles maintained by Android userspace
56850b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        addReservedSdpRecords(uuids);
56950b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh
57050b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        // Enable profiles maintained by Bluez userspace.
57174ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh        setBluetoothTetheringNative(true, BluetoothPanProfileHandler.NAP_ROLE,
57274ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                BluetoothPanProfileHandler.NAP_BRIDGE);
57350b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh
57450b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        // Add SDP records for profiles maintained by Bluez userspace
57550b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        uuids.add(BluetoothUuid.AudioSource);
57650b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        uuids.add(BluetoothUuid.AvrcpTarget);
57750b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        uuids.add(BluetoothUuid.NAP);
57850b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh
57950b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        // Cannot cast uuids.toArray directly since ParcelUuid is parcelable
58050b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        mAdapterUuids = new ParcelUuid[uuids.size()];
58150b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        for (int i = 0; i < uuids.size(); i++) {
58250b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh            mAdapterUuids[i] = uuids.get(i);
58350b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        }
58450b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh    }
58550b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh
5869efb1343a018c479ff57d70e8058658faa8a926dJaikumar Ganesh    /**
5879efb1343a018c479ff57d70e8058658faa8a926dJaikumar Ganesh     * This function is called from Bluetooth Event Loop when onPropertyChanged
5889efb1343a018c479ff57d70e8058658faa8a926dJaikumar Ganesh     * for adapter comes in with UUID property.
5899efb1343a018c479ff57d70e8058658faa8a926dJaikumar Ganesh     * @param uuidsThe uuids of adapter as reported by Bluez.
5909efb1343a018c479ff57d70e8058658faa8a926dJaikumar Ganesh     */
5917f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    /*package*/ synchronized void updateBluetoothState(String uuids) {
5927f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        ParcelUuid[] adapterUuids = convertStringToParcelUuid(uuids);
5939efb1343a018c479ff57d70e8058658faa8a926dJaikumar Ganesh
5947f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        if (mAdapterUuids != null &&
5957f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie            BluetoothUuid.containsAllUuids(adapterUuids, mAdapterUuids)) {
5967f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie            mBluetoothState.sendMessage(BluetoothAdapterStateMachine.SERVICE_RECORD_LOADED);
5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6007f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    /**
6018594394aadeaaa3f834d33d7b198fb071e0f31feMatthew Xie     * This method is called immediately before Bluetooth module is turned on after
6028594394aadeaaa3f834d33d7b198fb071e0f31feMatthew Xie     * the adapter became pariable.
6038594394aadeaaa3f834d33d7b198fb071e0f31feMatthew Xie     * It inits bond state and profile state before STATE_ON intent is broadcasted.
6048594394aadeaaa3f834d33d7b198fb071e0f31feMatthew Xie     */
6058594394aadeaaa3f834d33d7b198fb071e0f31feMatthew Xie    /*package*/ void initBluetoothAfterTurningOn() {
606d96daf1ae5f314ea5f56b3e0b465e3f3b0314235Matthew Xie        String discoverable = getProperty("Discoverable", false);
607d96daf1ae5f314ea5f56b3e0b465e3f3b0314235Matthew Xie        String timeout = getProperty("DiscoverableTimeout", false);
608d96daf1ae5f314ea5f56b3e0b465e3f3b0314235Matthew Xie        if (discoverable.equals("true") && Integer.valueOf(timeout) != 0) {
609d96daf1ae5f314ea5f56b3e0b465e3f3b0314235Matthew Xie            setAdapterPropertyBooleanNative("Discoverable", 0);
610d96daf1ae5f314ea5f56b3e0b465e3f3b0314235Matthew Xie        }
6118594394aadeaaa3f834d33d7b198fb071e0f31feMatthew Xie        mBondState.initBondState();
6128594394aadeaaa3f834d33d7b198fb071e0f31feMatthew Xie        initProfileState();
61398f06da8ed2851a768358de1979838ad1bb6d187Matthew Xie        getProfileProxy();
6148594394aadeaaa3f834d33d7b198fb071e0f31feMatthew Xie    }
6158594394aadeaaa3f834d33d7b198fb071e0f31feMatthew Xie
6168594394aadeaaa3f834d33d7b198fb071e0f31feMatthew Xie    /**
6177f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie     * This method is called immediately after Bluetooth module is turned on.
6187f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie     * It starts auto-connection and places bluetooth on sign onto the battery
6197f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie     * stats
6207f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie     */
6217f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    /*package*/ void runBluetooth() {
6227f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        autoConnect();
6237f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie
6247f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        // Log bluetooth on to battery stats.
6257f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        long ident = Binder.clearCallingIdentity();
6267f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        try {
6277f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie            mBatteryStats.noteBluetoothOn();
6287f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        } catch (RemoteException e) {
6297f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie            Log.e(TAG, "", e);
6307f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        } finally {
6317f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie            Binder.restoreCallingIdentity(ident);
6327f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        }
6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
635a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    /*package*/ synchronized boolean attemptAutoPair(String address) {
636a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        if (!mBondState.hasAutoPairingFailed(address) &&
637a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                !mBondState.isAutoPairingBlacklisted(address)) {
638a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            mBondState.attempt(address);
639a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            setPin(address, BluetoothDevice.convertPinToBytes("0000"));
640a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            return true;
641a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        }
642a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        return false;
643a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    }
644a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh
645f487d72215421a02e5a1b2fbff4618bc5ee185cbJaikumar Ganesh    /*package*/ synchronized boolean isFixedPinZerosAutoPairKeyboard(String address) {
646f487d72215421a02e5a1b2fbff4618bc5ee185cbJaikumar Ganesh        // Check for keyboards which have fixed PIN 0000 as the pairing pin
647f487d72215421a02e5a1b2fbff4618bc5ee185cbJaikumar Ganesh        return mBondState.isFixedPinZerosAutoPairKeyboard(address);
648f487d72215421a02e5a1b2fbff4618bc5ee185cbJaikumar Ganesh    }
649f487d72215421a02e5a1b2fbff4618bc5ee185cbJaikumar Ganesh
650a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    /*package*/ synchronized void onCreatePairedDeviceResult(String address, int result) {
651a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        if (result == BluetoothDevice.BOND_SUCCESS) {
652a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            setBondState(address, BluetoothDevice.BOND_BONDED);
653a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            if (mBondState.isAutoPairingAttemptsInProgress(address)) {
654a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                mBondState.clearPinAttempts(address);
655a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            }
656a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        } else if (result == BluetoothDevice.UNBOND_REASON_AUTH_FAILED &&
657a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                mBondState.getAttempt(address) == 1) {
658a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            mBondState.addAutoPairingFailure(address);
659a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            pairingAttempt(address, result);
660a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        } else if (result == BluetoothDevice.UNBOND_REASON_REMOTE_DEVICE_DOWN &&
661a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh              mBondState.isAutoPairingAttemptsInProgress(address)) {
662a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            pairingAttempt(address, result);
663a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        } else {
664a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            setBondState(address, BluetoothDevice.BOND_NONE, result);
665a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            if (mBondState.isAutoPairingAttemptsInProgress(address)) {
666a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                mBondState.clearPinAttempts(address);
667a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            }
668a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        }
669a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    }
670a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh
671a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    /*package*/ synchronized String getPendingOutgoingBonding() {
672a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        return mBondState.getPendingOutgoingBonding();
673a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    }
674a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh
675a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    private void pairingAttempt(String address, int result) {
676a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        // This happens when our initial guess of "0000" as the pass key
677a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        // fails. Try to create the bond again and display the pin dialog
678a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        // to the user. Use back-off while posting the delayed
679a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        // message. The initial value is
680a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        // INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY and the max value is
681a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        // MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY. If the max value is
682a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        // reached, display an error to the user.
683a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        int attempt = mBondState.getAttempt(address);
684a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        if (attempt * INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY >
685a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                    MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY) {
686a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            mBondState.clearPinAttempts(address);
687a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            setBondState(address, BluetoothDevice.BOND_NONE, result);
688a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            return;
689a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        }
690a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh
691a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        Message message = mHandler.obtainMessage(MESSAGE_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY);
692a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        message.obj = address;
693a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        boolean postResult =  mHandler.sendMessageDelayed(message,
694a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                                        attempt * INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY);
695a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        if (!postResult) {
696a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            mBondState.clearPinAttempts(address);
697a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            setBondState(address,
698a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh                    BluetoothDevice.BOND_NONE, result);
699a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh            return;
700a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        }
7019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7039a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    /*package*/ BluetoothDevice getRemoteDevice(String address) {
7049a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        return mAdapter.getRemoteDevice(address);
7059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static String toBondStateString(int bondState) {
7089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        switch (bondState) {
709005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        case BluetoothDevice.BOND_NONE:
7109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "not bonded";
7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case BluetoothDevice.BOND_BONDING:
7129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "bonding";
7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case BluetoothDevice.BOND_BONDED:
7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "bonded";
7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        default:
7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "??????";
7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean setName(String name) {
7219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
7229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (name == null) {
7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
7259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
726d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setPropertyString("Name", name);
7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
729d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    //TODO(): setPropertyString, setPropertyInteger, setPropertyBoolean
730d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    // Either have a single property function with Object as the parameter
731d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    // or have a function for each property and then obfuscate in the JNI layer.
732d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    // The following looks dirty.
733d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private boolean setPropertyString(String key, String value) {
7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
7358c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
736d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setAdapterPropertyStringNative(key, value);
7379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
739d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private boolean setPropertyInteger(String key, int value) {
740d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
7418c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
742d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setAdapterPropertyIntegerNative(key, value);
743d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
7449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
745d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private boolean setPropertyBoolean(String key, boolean value) {
746d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
7478c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
748d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setAdapterPropertyBooleanNative(key, value ? 1 : 0);
7499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
751d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /**
752d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Set the discoverability window for the device.  A timeout of zero
753d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * makes the device permanently discoverable (if the device is
754d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * discoverable).  Setting the timeout to a nonzero value does not make
755d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * a device discoverable; you need to call setMode() to make the device
756d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * explicitly discoverable.
757d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     *
758f51eadaf1f83abfe16a609a4ded6d789494689b2Jake Hamby     * @param timeout The discoverable timeout in seconds.
759d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     */
760d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized boolean setDiscoverableTimeout(int timeout) {
7619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
7629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
763d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return setPropertyInteger("DiscoverableTimeout", timeout);
7649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
76612835478ee687a493d1b5882e67b6725bd539c26Nick Pelly    public synchronized boolean setScanMode(int mode, int duration) {
76718b1e79a123b979d25bfa5d0b0ee5d0382dbd64bNick Pelly        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS,
76818b1e79a123b979d25bfa5d0b0ee5d0382dbd64bNick Pelly                                                "Need WRITE_SECURE_SETTINGS permission");
7699a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        boolean pairable;
7709a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        boolean discoverable;
77112835478ee687a493d1b5882e67b6725bd539c26Nick Pelly
772de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        switch (mode) {
773de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.SCAN_MODE_NONE:
774d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            pairable = false;
775d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            discoverable = false;
776de893f550301a60274e87aa8168225e7a7a42184Nick Pelly            break;
777de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
778d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            pairable = true;
779d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            discoverable = false;
780005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            break;
781de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
782d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            pairable = true;
783d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            discoverable = true;
78412835478ee687a493d1b5882e67b6725bd539c26Nick Pelly            if (DBG) Log.d(TAG, "BT Discoverable for " + duration + " seconds");
785005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            break;
786de893f550301a60274e87aa8168225e7a7a42184Nick Pelly        default:
787de893f550301a60274e87aa8168225e7a7a42184Nick Pelly            Log.w(TAG, "Requested invalid scan mode " + mode);
788de893f550301a60274e87aa8168225e7a7a42184Nick Pelly            return false;
789d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
79114e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie        setPropertyBoolean("Discoverable", discoverable);
79214e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie        setPropertyBoolean("Pairable", pairable);
793d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return true;
7949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
79614e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie    /**
79714e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie     * @param on true set the local Bluetooth module to be connectable
79814e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie     *                The dicoverability is recovered to what it was before
79914e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie     *                switchConnectable(false) call
80014e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie     *           false set the local Bluetooth module to be not connectable
80114e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie     *                 and not dicoverable
80214e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie     */
80314e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie    /*package*/ synchronized void switchConnectable(boolean on) {
80414e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie        setAdapterPropertyBooleanNative("Powered", on ? 1 : 0);
80514e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie    }
80614e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie
80714e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie    /*package*/ synchronized void setPairable() {
80814e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie        String pairableString = getProperty("Pairable", false);
80914e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie        if (pairableString == null) {
81014e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie            Log.e(TAG, "null pairableString");
81114e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie            return;
81214e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie        }
81314e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie        if (pairableString.equals("false")) {
81414e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie            setAdapterPropertyBooleanNative("Pairable", 1);
81514e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie        }
81614e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie    }
81714e48e91f6def5448db9994cb13ddcdc676cba53Matthew Xie
81844b58ab89e59b3d8241901232c8f7dc9617b206eMatthew Xie    /*package*/ String getProperty(String name, boolean checkState) {
819a66590ed78d0ec8e837dab80a4376a10d7023e9aJaikumar Ganesh        // If checkState is false, check if the event loop is running.
820a66590ed78d0ec8e837dab80a4376a10d7023e9aJaikumar Ganesh        // before making the call to Bluez
821a66590ed78d0ec8e837dab80a4376a10d7023e9aJaikumar Ganesh        if (checkState) {
822a66590ed78d0ec8e837dab80a4376a10d7023e9aJaikumar Ganesh            if (!isEnabledInternal()) return null;
823a66590ed78d0ec8e837dab80a4376a10d7023e9aJaikumar Ganesh        } else if (!mEventLoop.isEventLoopRunning()) {
824a66590ed78d0ec8e837dab80a4376a10d7023e9aJaikumar Ganesh            return null;
825a66590ed78d0ec8e837dab80a4376a10d7023e9aJaikumar Ganesh        }
826a66590ed78d0ec8e837dab80a4376a10d7023e9aJaikumar Ganesh
8279a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        return mAdapterProperties.getProperty(name);
828b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh    }
829b148bc844e5eddb07bef2fd1b4b754716decb43eJaikumar Ganesh
8309a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    BluetoothAdapterProperties getAdapterProperties() {
8319a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        return mAdapterProperties;
8329a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    }
8339a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
8349a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    BluetoothDeviceProperties getDeviceProperties() {
8359a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        return mDeviceProperties;
8369a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    }
8379a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
8389a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    boolean isRemoteDeviceInCache(String address) {
8399a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        return mDeviceProperties.isInCache(address);
8409a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    }
8419a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
8429a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    void setRemoteDeviceProperty(String address, String name, String value) {
8439a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        mDeviceProperties.setProperty(address, name, value);
8449a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    }
8459a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
8469a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    void updateRemoteDevicePropertiesCache(String address) {
8479a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        mDeviceProperties.updateCache(address);
8489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
850d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized String getAddress() {
851d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
852a66590ed78d0ec8e837dab80a4376a10d7023e9aJaikumar Ganesh        // Don't check state since we want to provide address, even if BT is off
853a66590ed78d0ec8e837dab80a4376a10d7023e9aJaikumar Ganesh        return getProperty("Address", false);
8549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
856d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized String getName() {
8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
858a66590ed78d0ec8e837dab80a4376a10d7023e9aJaikumar Ganesh        // Don't check state since we want to provide name, even if BT is off
859a66590ed78d0ec8e837dab80a4376a10d7023e9aJaikumar Ganesh        return getProperty("Name", false);
8609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
86244b58ab89e59b3d8241901232c8f7dc9617b206eMatthew Xie    public ParcelUuid[] getUuids() {
86358b93c36409c7fb91a644605f004b6d247d9b540Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
864a66590ed78d0ec8e837dab80a4376a10d7023e9aJaikumar Ganesh        String value =  getProperty("UUIDs", true);
86558b93c36409c7fb91a644605f004b6d247d9b540Jaikumar Ganesh        if (value == null) return null;
86650b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh        return convertStringToParcelUuid(value);
86750b40cec9c43eeeb9389ba2a99bcffd160246132Jaikumar Ganesh    }
86858b93c36409c7fb91a644605f004b6d247d9b540Jaikumar Ganesh
86944b58ab89e59b3d8241901232c8f7dc9617b206eMatthew Xie    private ParcelUuid[] convertStringToParcelUuid(String value) {
87058b93c36409c7fb91a644605f004b6d247d9b540Jaikumar Ganesh        String[] uuidStrings = null;
87158b93c36409c7fb91a644605f004b6d247d9b540Jaikumar Ganesh        // The UUIDs are stored as a "," separated string.
87258b93c36409c7fb91a644605f004b6d247d9b540Jaikumar Ganesh        uuidStrings = value.split(",");
87358b93c36409c7fb91a644605f004b6d247d9b540Jaikumar Ganesh        ParcelUuid[] uuids = new ParcelUuid[uuidStrings.length];
87458b93c36409c7fb91a644605f004b6d247d9b540Jaikumar Ganesh
87558b93c36409c7fb91a644605f004b6d247d9b540Jaikumar Ganesh        for (int i = 0; i < uuidStrings.length; i++) {
87658b93c36409c7fb91a644605f004b6d247d9b540Jaikumar Ganesh            uuids[i] = ParcelUuid.fromString(uuidStrings[i]);
87758b93c36409c7fb91a644605f004b6d247d9b540Jaikumar Ganesh        }
87858b93c36409c7fb91a644605f004b6d247d9b540Jaikumar Ganesh        return uuids;
87958b93c36409c7fb91a644605f004b6d247d9b540Jaikumar Ganesh    }
88058b93c36409c7fb91a644605f004b6d247d9b540Jaikumar Ganesh
8819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
882d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Returns the user-friendly name of a remote device.  This value is
883d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * returned from our local cache, which is updated when onPropertyChange
884d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * event is received.
885d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Do not expect to retrieve the updated remote name immediately after
886d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * changing the name on the remote device.
8879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
888d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * @param address Bluetooth address of remote device.
889d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     *
890d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * @return The user-friendly name of the specified remote device.
8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
892d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized String getRemoteName(String address) {
893d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
894005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
895d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return null;
896d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
8979a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        return mDeviceProperties.getProperty(address, "Name");
8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
901269e81a563cfe080d7f241d0d46411d3c946c111Matthew Xie     * Returns alias of a remote device.  This value is returned from our
902269e81a563cfe080d7f241d0d46411d3c946c111Matthew Xie     * local cache, which is updated when onPropertyChange event is received.
903269e81a563cfe080d7f241d0d46411d3c946c111Matthew Xie     *
904269e81a563cfe080d7f241d0d46411d3c946c111Matthew Xie     * @param address Bluetooth address of remote device.
905269e81a563cfe080d7f241d0d46411d3c946c111Matthew Xie     *
906269e81a563cfe080d7f241d0d46411d3c946c111Matthew Xie     * @return The alias of the specified remote device.
907269e81a563cfe080d7f241d0d46411d3c946c111Matthew Xie     */
908269e81a563cfe080d7f241d0d46411d3c946c111Matthew Xie    public synchronized String getRemoteAlias(String address) {
909269e81a563cfe080d7f241d0d46411d3c946c111Matthew Xie
910269e81a563cfe080d7f241d0d46411d3c946c111Matthew Xie        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
911269e81a563cfe080d7f241d0d46411d3c946c111Matthew Xie        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
912269e81a563cfe080d7f241d0d46411d3c946c111Matthew Xie            return null;
913269e81a563cfe080d7f241d0d46411d3c946c111Matthew Xie        }
914269e81a563cfe080d7f241d0d46411d3c946c111Matthew Xie        return mDeviceProperties.getProperty(address, "Alias");
915269e81a563cfe080d7f241d0d46411d3c946c111Matthew Xie    }
916269e81a563cfe080d7f241d0d46411d3c946c111Matthew Xie
917269e81a563cfe080d7f241d0d46411d3c946c111Matthew Xie    /**
918269e81a563cfe080d7f241d0d46411d3c946c111Matthew Xie     * Set the alias of a remote device.
919269e81a563cfe080d7f241d0d46411d3c946c111Matthew Xie     *
920269e81a563cfe080d7f241d0d46411d3c946c111Matthew Xie     * @param address Bluetooth address of remote device.
921269e81a563cfe080d7f241d0d46411d3c946c111Matthew Xie     * @param alias new alias to change to
922269e81a563cfe080d7f241d0d46411d3c946c111Matthew Xie     * @return true on success, false on error
923269e81a563cfe080d7f241d0d46411d3c946c111Matthew Xie     */
924269e81a563cfe080d7f241d0d46411d3c946c111Matthew Xie    public synchronized boolean setRemoteAlias(String address, String alias) {
925269e81a563cfe080d7f241d0d46411d3c946c111Matthew Xie        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
926269e81a563cfe080d7f241d0d46411d3c946c111Matthew Xie        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
927269e81a563cfe080d7f241d0d46411d3c946c111Matthew Xie            return false;
928269e81a563cfe080d7f241d0d46411d3c946c111Matthew Xie        }
929269e81a563cfe080d7f241d0d46411d3c946c111Matthew Xie
930269e81a563cfe080d7f241d0d46411d3c946c111Matthew Xie        return setDevicePropertyStringNative(getObjectPathFromAddress(address),
931269e81a563cfe080d7f241d0d46411d3c946c111Matthew Xie                                             "Alias", alias);
932269e81a563cfe080d7f241d0d46411d3c946c111Matthew Xie    }
933269e81a563cfe080d7f241d0d46411d3c946c111Matthew Xie
934269e81a563cfe080d7f241d0d46411d3c946c111Matthew Xie    /**
9359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Get the discoverability window for the device.  A timeout of zero
9369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * means that the device is permanently discoverable (if the device is
9379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * in the discoverable mode).
9389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
9399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The discoverability window of the device, in seconds.  A negative
9409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         value indicates an error.
9419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
94244b58ab89e59b3d8241901232c8f7dc9617b206eMatthew Xie    public int getDiscoverableTimeout() {
9439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
944a66590ed78d0ec8e837dab80a4376a10d7023e9aJaikumar Ganesh        String timeout = getProperty("DiscoverableTimeout", true);
945d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (timeout != null)
946d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh           return Integer.valueOf(timeout);
947d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        else
948d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return -1;
9499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
95144b58ab89e59b3d8241901232c8f7dc9617b206eMatthew Xie    public int getScanMode() {
9529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
9538c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal())
954de893f550301a60274e87aa8168225e7a7a42184Nick Pelly            return BluetoothAdapter.SCAN_MODE_NONE;
955d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
956a66590ed78d0ec8e837dab80a4376a10d7023e9aJaikumar Ganesh        boolean pairable = getProperty("Pairable", true).equals("true");
957a66590ed78d0ec8e837dab80a4376a10d7023e9aJaikumar Ganesh        boolean discoverable = getProperty("Discoverable", true).equals("true");
958d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return bluezStringToScanMode (pairable, discoverable);
9599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
961d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized boolean startDiscovery() {
9629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
9639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
9648c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
9658c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
966d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return startDiscoveryNative();
9679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
969d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    public synchronized boolean cancelDiscovery() {
9709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
9719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
9728c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
9738c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
974d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return stopDiscoveryNative();
975d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
976d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
97744b58ab89e59b3d8241901232c8f7dc9617b206eMatthew Xie    public boolean isDiscovering() {
978d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
979d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
980a66590ed78d0ec8e837dab80a4376a10d7023e9aJaikumar Ganesh        String discoveringProperty = getProperty("Discovering", false);
9818594394aadeaaa3f834d33d7b198fb071e0f31feMatthew Xie        if (discoveringProperty == null) {
9828594394aadeaaa3f834d33d7b198fb071e0f31feMatthew Xie            return false;
9838594394aadeaaa3f834d33d7b198fb071e0f31feMatthew Xie        }
9848594394aadeaaa3f834d33d7b198fb071e0f31feMatthew Xie
9858594394aadeaaa3f834d33d7b198fb071e0f31feMatthew Xie        return discoveringProperty.equals("true");
9869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
988cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    private boolean isBondingFeasible(String address) {
9899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
9909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
9918c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
9928c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
993005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
9949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
9959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        address = address.toUpperCase();
9979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9982092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        if (mBondState.getPendingOutgoingBonding() != null) {
9999a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            Log.d(TAG, "Ignoring createBond(): another device is bonding");
10009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // a different device is currently bonding, fail
10019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
10029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Check for bond state only if we are not performing auto
10059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // pairing exponential back-off attempts.
10069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mBondState.isAutoPairingAttemptsInProgress(address) &&
1007005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly                mBondState.getBondState(address) != BluetoothDevice.BOND_NONE) {
10089a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            Log.d(TAG, "Ignoring createBond(): this device is already bonding or bonded");
10099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
10109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10123fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        if (address.equals(mDockAddress)) {
10133fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            if (!writeDockPin()) {
10149a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                Log.e(TAG, "Error while writing Pin for the dock");
10153fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh                return false;
10163fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh            }
10173fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh        }
1018cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        return true;
1019cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    }
10203fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
1021cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    public synchronized boolean createBond(String address) {
1022cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (!isBondingFeasible(address)) return false;
1023cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
1024cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (!createPairedDeviceNative(address, 60000  /*1 minute*/ )) {
10259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
10269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10282092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        mBondState.setPendingOutgoingBonding(address);
10299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mBondState.setBondState(address, BluetoothDevice.BOND_BONDING);
10302092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
10319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
10329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1034cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    public synchronized boolean createBondOutOfBand(String address, byte[] hash,
1035cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh                                                    byte[] randomizer) {
1036cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (!isBondingFeasible(address)) return false;
10373fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
1038cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (!createPairedDeviceOutOfBandNative(address, 60000 /* 1 minute */)) {
10399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
10409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1042cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        setDeviceOutOfBandData(address, hash, randomizer);
10432092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh        mBondState.setPendingOutgoingBonding(address);
10449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mBondState.setBondState(address, BluetoothDevice.BOND_BONDING);
10452092361d586a20190c9137fb3cc9434cdc9ec99fJaikumar Ganesh
10469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
10479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1049cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    public synchronized boolean setDeviceOutOfBandData(String address, byte[] hash,
1050cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh            byte[] randomizer) {
1051cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1052cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh                                                "Need BLUETOOTH_ADMIN permission");
1053cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (!isEnabledInternal()) return false;
1054cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
1055cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        Pair <byte[], byte[]> value = new Pair<byte[], byte[]>(hash, randomizer);
1056cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
1057cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (DBG) {
10589a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            Log.d(TAG, "Setting out of band data for: " + address + ":" +
10599a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                  Arrays.toString(hash) + ":" + Arrays.toString(randomizer));
1060cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        }
1061cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
1062cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        mDeviceOobData.put(address, value);
1063cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        return true;
1064cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    }
1065cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
1066cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    Pair<byte[], byte[]> getDeviceOutOfBandData(BluetoothDevice device) {
1067cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        return mDeviceOobData.get(device.getAddress());
1068cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    }
1069cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
1070cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
1071cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    public synchronized byte[] readOutOfBandData() {
1072cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
1073cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh                                                "Need BLUETOOTH permission");
1074cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (!isEnabledInternal()) return null;
1075cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
1076cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        return readAdapterOutOfBandDataNative();
1077cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    }
1078cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
10799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean cancelBondProcess(String address) {
10809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
10819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
10828c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
10838c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1084005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
10859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
10869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        address = address.toUpperCase();
10889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mBondState.getBondState(address) != BluetoothDevice.BOND_BONDING) {
10899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
10909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1092005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        mBondState.setBondState(address, BluetoothDevice.BOND_NONE,
10939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
1094d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        cancelDeviceCreationNative(address);
10959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
10969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean removeBond(String address) {
10999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
11009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
11018c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
11028c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1103005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
11049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
11059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1106f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
11079b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (state != null) {
1108f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            state.sendMessage(BluetoothDeviceProfileState.UNPAIR);
11099b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            return true;
11109b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        } else {
11119b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            return false;
11129b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
11139b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
11149b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
11159b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public synchronized boolean removeBondInternal(String address) {
1116cc2c06656ceafbcd91ec5b679aa6c9eae0d9982cJaikumar Ganesh        // Unset the trusted device state and then unpair
1117cc2c06656ceafbcd91ec5b679aa6c9eae0d9982cJaikumar Ganesh        setTrust(address, false);
1118d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return removeDeviceNative(getObjectPathFromAddress(address));
11199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized String[] listBonds() {
11229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
11239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mBondState.listInState(BluetoothDevice.BOND_BONDED);
11249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1126a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    /*package*/ synchronized String[] listInState(int state) {
1127a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh      return mBondState.listInState(state);
1128a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    }
1129a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh
11309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized int getBondState(String address) {
11319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1132005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1133b24e11baac589fe16426f2d243b460ab84991c7bNick Pelly            return BluetoothDevice.ERROR;
11349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mBondState.getBondState(address.toUpperCase());
11369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1138a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    /*package*/ synchronized boolean setBondState(String address, int state) {
1139a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        return setBondState(address, state, 0);
1140a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    }
1141a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh
1142a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    /*package*/ synchronized boolean setBondState(String address, int state, int reason) {
1143ae5fbb0b4363a2a399e92e310777d7a955a25370Arek Lichwa        mBondState.setBondState(address.toUpperCase(), state, reason);
1144a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh        return true;
1145a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh    }
1146a224f70b1efc29d9698da5b5c143251a43838f2bJaikumar Ganesh
11473fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    public synchronized boolean isBluetoothDock(String address) {
11486e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh        SharedPreferences sp = mContext.getSharedPreferences(SHARED_PREFERENCES_NAME,
11499a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                Context.MODE_PRIVATE);
11506e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh
11516e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh        return sp.contains(SHARED_PREFERENCE_DOCK_ADDRESS + address);
11523fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh    }
11533fbf7b62bb48b10316353087d09cc3720af00642Jaikumar Ganesh
11549488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh    /*package*/ String[] getRemoteDeviceProperties(String address) {
11558c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return null;
11568c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
11579488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh        String objectPath = getObjectPathFromAddress(address);
11589488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh        return (String [])getDevicePropertiesNative(objectPath);
11599488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh    }
11609488cbd0b9ce0a9b49647910e76c6fa910f948eaJaikumar Ganesh
11619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1162efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * Sets the remote device trust state.
1163efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     *
1164efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * @return boolean to indicate operation success or fail
1165efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     */
1166efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    public synchronized boolean setTrust(String address, boolean value) {
1167005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1168e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly            mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1169e6ee3be1c254404dad842298f6f56c11cc6c7ac8Nick Pelly                    "Need BLUETOOTH_ADMIN permission");
1170efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            return false;
1171efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        }
1172efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue
11738c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
11748c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
11759a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        return setDevicePropertyBooleanNative(
11769a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                getObjectPathFromAddress(address), "Trusted", value ? 1 : 0);
1177efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    }
1178efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue
1179efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    /**
1180efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * Gets the remote device trust state as boolean.
1181efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * Note: this value may be
1182efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     * retrieved from cache if we retrieved the data before *
1183efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     *
11849a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby     * @return boolean to indicate trusted or untrusted state
1185efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue     */
1186efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    public synchronized boolean getTrustState(String address) {
1187005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1188efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1189efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            return false;
1190efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        }
1191efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue
11929a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        String val = mDeviceProperties.getProperty(address, "Trusted");
1193efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        if (val == null) {
1194efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue            return false;
1195efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        } else {
11969a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            return val.equals("true");
1197efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue        }
1198efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    }
1199efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue
1200efa1dd716da3372cc74a201d11de5e0ef1a9fe9aLixin Yue    /**
1201d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Gets the remote major, minor classes encoded as a 32-bit
12029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * integer.
12039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
12049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Note: this value is retrieved from cache, because we get it during
12059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *       remote-device discovery.
12069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
12079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return 32-bit integer encoding the remote major, minor, and service
12089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         classes.
12099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
12109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized int getRemoteClass(String address) {
1211005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1212ea600ccfb7568f60377c4abc85f56c80af7fdbfcNick Pelly            mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1213ea600ccfb7568f60377c4abc85f56c80af7fdbfcNick Pelly            return BluetoothClass.ERROR;
12149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12159a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        String val = mDeviceProperties.getProperty(address, "Class");
1216d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (val == null)
1217d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return BluetoothClass.ERROR;
1218d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        else {
1219d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return Integer.valueOf(val);
1220d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
12219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1222d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
12239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1225dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh     * Gets the UUIDs supported by the remote device
12269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1227dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh     * @return array of 128bit ParcelUuids
12289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1229dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh    public synchronized ParcelUuid[] getRemoteUuids(String address) {
12309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1231005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
12329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return null;
12339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12341caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        return getUuidFromCache(address);
12351caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    }
12361caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
12379a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    ParcelUuid[] getUuidFromCache(String address) {
12389a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        String value = mDeviceProperties.getProperty(address, "UUIDs");
1239dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        if (value == null) return null;
1240dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh
1241dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        String[] uuidStrings = null;
1242d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        // The UUIDs are stored as a "," separated string.
1243dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        uuidStrings = value.split(",");
1244dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        ParcelUuid[] uuids = new ParcelUuid[uuidStrings.length];
1245dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh
1246dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        for (int i = 0; i < uuidStrings.length; i++) {
1247dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh            uuids[i] = ParcelUuid.fromString(uuidStrings[i]);
1248dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh        }
1249d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return uuids;
12509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
125216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    /**
125316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * Connect and fetch new UUID's using SDP.
125416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * The UUID's found are broadcast as intents.
125516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * Optionally takes a uuid and callback to fetch the RFCOMM channel for the
125616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * a given uuid.
125716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * TODO: Don't wait UUID_INTENT_DELAY to broadcast UUID intents on success
125816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * TODO: Don't wait UUID_INTENT_DELAY to handle the failure case for
125916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * callback and broadcast intents.
126016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     */
126116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    public synchronized boolean fetchRemoteUuids(String address, ParcelUuid uuid,
126216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            IBluetoothCallback callback) {
12631caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
12648c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
12658c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
12661caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
12671caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            return false;
12681caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        }
12691caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
127016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        RemoteService service = new RemoteService(address, uuid);
127116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        if (uuid != null && mUuidCallbackTracker.get(service) != null) {
127216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            // An SDP query for this address & uuid is already in progress
127316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            // Do not add this callback for the uuid
127416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            return false;
127516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
127616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
12771caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        if (mUuidIntentTracker.contains(address)) {
12781caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            // An SDP query for this address is already in progress
127916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            // Add this uuid onto the in-progress SDP query
128016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (uuid != null) {
128116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                mUuidCallbackTracker.put(new RemoteService(address, uuid), callback);
128216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
12831caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh            return true;
12841caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        }
12851caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
1286421f0101087bbede1152ccc6d8212f6686a10e54Jaikumar Ganesh        // If the device is already created, we will
1287421f0101087bbede1152ccc6d8212f6686a10e54Jaikumar Ganesh        // do the SDP on the callback of createDeviceNative.
1288421f0101087bbede1152ccc6d8212f6686a10e54Jaikumar Ganesh        boolean ret= createDeviceNative(address);
12891caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
12901caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        mUuidIntentTracker.add(address);
129116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        if (uuid != null) {
129216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            mUuidCallbackTracker.put(new RemoteService(address, uuid), callback);
129316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
12941caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
12951caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        Message message = mHandler.obtainMessage(MESSAGE_UUID_INTENT);
12961caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        message.obj = address;
12971caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        mHandler.sendMessageDelayed(message, UUID_INTENT_DELAY);
12981caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh        return ret;
12991caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    }
13001caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
13019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1302d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * Gets the rfcomm channel associated with the UUID.
130316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly     * Pulls records from the cache only.
13049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1305d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * @param address Address of the remote device
1306dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh     * @param uuid ParcelUuid of the service attribute
13079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1308d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh     * @return rfcomm channel associated with the service attribute
130910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh     *         -1 on error
13109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1311dd0463aef18d251c741bfc9dc7a2787443ef36f1Jaikumar Ganesh    public int getRemoteServiceChannel(String address, ParcelUuid uuid) {
13129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
13138c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return -1;
13148c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1315005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
1316b24e11baac589fe16426f2d243b460ab84991c7bNick Pelly            return BluetoothDevice.ERROR;
13179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
131810eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        // Check if we are recovering from a crash.
131910eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        if (mDeviceProperties.isEmpty()) {
13209a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            if (mDeviceProperties.updateCache(address) == null)
132110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh                return -1;
132210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        }
132310eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
132410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        Map<ParcelUuid, Integer> value = mDeviceServiceChannelCache.get(address);
132510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        if (value != null && value.containsKey(uuid))
132610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            return value.get(uuid);
132710eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        return -1;
13289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public synchronized boolean setPin(String address, byte[] pin) {
13319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
13329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
13338c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
13348c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
13359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (pin == null || pin.length <= 0 || pin.length > 16 ||
1336005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly            !BluetoothAdapter.checkBluetoothAddress(address)) {
13379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
13389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        address = address.toUpperCase();
13409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
13419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (data == null) {
13429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.w(TAG, "setPin(" + address + ") called but no native data available, " +
13439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                  "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
13449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                  " or by bluez.\n");
13459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
13469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // bluez API wants pin as a string
13489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String pinString;
13499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
13509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pinString = new String(pin, "UTF8");
13519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (UnsupportedEncodingException uee) {
13529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.e(TAG, "UTF8 not supported?!?");
13539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
13549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return setPinNative(address, pinString, data.intValue());
13569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1358b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    public synchronized boolean setPasskey(String address, int passkey) {
1359b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1360b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                                                "Need BLUETOOTH_ADMIN permission");
13618c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
13628c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1363005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (passkey < 0 || passkey > 999999 || !BluetoothAdapter.checkBluetoothAddress(address)) {
1364b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            return false;
1365b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        }
1366b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        address = address.toUpperCase();
1367b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
1368b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        if (data == null) {
1369b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            Log.w(TAG, "setPasskey(" + address + ") called but no native data available, " +
1370b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                  "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
1371b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                  " or by bluez.\n");
1372b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            return false;
1373b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        }
1374b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        return setPasskeyNative(address, passkey, data.intValue());
1375b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    }
1376b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh
1377b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    public synchronized boolean setPairingConfirmation(String address, boolean confirm) {
1378b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1379b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                                                "Need BLUETOOTH_ADMIN permission");
13808c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
13818c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1382b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        address = address.toUpperCase();
1383b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
1384b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        if (data == null) {
1385b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            Log.w(TAG, "setPasskey(" + address + ") called but no native data available, " +
1386b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                  "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
1387b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                  " or by bluez.\n");
1388b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            return false;
1389b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        }
1390b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        return setPairingConfirmationNative(address, confirm, data.intValue());
1391b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    }
1392b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh
1393cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    public synchronized boolean setRemoteOutOfBandData(String address) {
1394cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
1395cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh                                                "Need BLUETOOTH_ADMIN permission");
1396cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (!isEnabledInternal()) return false;
1397cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        address = address.toUpperCase();
1398cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
1399cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (data == null) {
1400cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh            Log.w(TAG, "setRemoteOobData(" + address + ") called but no native data available, " +
1401cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh                  "ignoring. Maybe the PasskeyAgent Request was cancelled by the remote device" +
1402cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh                  " or by bluez.\n");
1403cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh            return false;
1404cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        }
1405cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
1406cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        Pair<byte[], byte[]> val = mDeviceOobData.get(address);
1407cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        byte[] hash, randomizer;
1408cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        if (val == null) {
1409cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh            // TODO: check what should be passed in this case.
1410cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh            hash = new byte[16];
1411cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh            randomizer = new byte[16];
1412cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        } else {
1413cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh            hash = val.first;
1414cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh            randomizer = val.second;
1415cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        }
1416cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh        return setRemoteOutOfBandDataNative(address, hash, randomizer, data.intValue());
1417cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    }
1418cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
1419b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    public synchronized boolean cancelPairingUserInput(String address) {
14209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
14219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                                "Need BLUETOOTH_ADMIN permission");
14228c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return false;
14238c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
1424005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
14259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
14269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1427005b228cdfb369d9b3b325884c0337ba5968bf8cNick Pelly        mBondState.setBondState(address, BluetoothDevice.BOND_NONE,
1428397d8f4f4829a45f4fe7a672cc395466bbc0f442Jaikumar Ganesh                BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
14299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        address = address.toUpperCase();
14309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
14319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (data == null) {
1432b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            Log.w(TAG, "cancelUserInputNative(" + address + ") called but no native data " +
1433b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                "available, ignoring. Maybe the PasskeyAgent Request was already cancelled " +
1434b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh                "by the remote or by bluez.\n");
14359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
14369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1437b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh        return cancelPairingUserInputNative(address, data.intValue());
14389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14408c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh    /*package*/ void updateDeviceServiceChannelCache(String address) {
14419a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        if (DBG) Log.d(TAG, "updateDeviceServiceChannelCache(" + address + ")");
14429a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
144310eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        // We are storing the rfcomm channel numbers only for the uuids
144410eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        // we are interested in.
14459a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        ParcelUuid[] deviceUuids = getRemoteUuids(address);
144616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
14479a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        ArrayList<ParcelUuid> applicationUuids = new ArrayList<ParcelUuid>();
144816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
144916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        synchronized (this) {
145016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            for (RemoteService service : mUuidCallbackTracker.keySet()) {
145116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (service.address.equals(address)) {
145216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    applicationUuids.add(service.uuid);
145316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                }
145416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
145516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
145610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
14579a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        Map <ParcelUuid, Integer> uuidToChannelMap = new HashMap<ParcelUuid, Integer>();
145816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
145916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        // Retrieve RFCOMM channel for default uuids
146016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        for (ParcelUuid uuid : RFCOMM_UUIDS) {
146110eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            if (BluetoothUuid.isUuidPresent(deviceUuids, uuid)) {
14629a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                int channel = getDeviceServiceChannelForUuid(address, uuid);
14639a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                uuidToChannelMap.put(uuid, channel);
14649a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                if (DBG) Log.d(TAG, "\tuuid(system): " + uuid + " " + channel);
146510eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh            }
146610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh        }
146716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        // Retrieve RFCOMM channel for application requested uuids
146816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        for (ParcelUuid uuid : applicationUuids) {
146916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (BluetoothUuid.isUuidPresent(deviceUuids, uuid)) {
14709a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                int channel = getDeviceServiceChannelForUuid(address, uuid);
14719a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                uuidToChannelMap.put(uuid, channel);
14729a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                if (DBG) Log.d(TAG, "\tuuid(application): " + uuid + " " + channel);
147316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
147416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
147516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
147616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        synchronized (this) {
147716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            // Make application callbacks
147816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            for (Iterator<RemoteService> iter = mUuidCallbackTracker.keySet().iterator();
147916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    iter.hasNext();) {
148016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                RemoteService service = iter.next();
148116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (service.address.equals(address)) {
14829a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                    if (uuidToChannelMap.containsKey(service.uuid)) {
14839a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                        int channel = uuidToChannelMap.get(service.uuid);
14849a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
14859a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                        if (DBG) Log.d(TAG, "Making callback for " + service.uuid +
14869a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                                    " with result " + channel);
148716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        IBluetoothCallback callback = mUuidCallbackTracker.get(service);
148816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        if (callback != null) {
148916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                            try {
149016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                                callback.onRfcommChannelFound(channel);
149116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                            } catch (RemoteException e) {Log.e(TAG, "", e);}
149216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        }
149316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
149416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        iter.remove();
149516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    }
149616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                }
149716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
149816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
149916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            // Update cache
15009a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            mDeviceServiceChannelCache.put(address, uuidToChannelMap);
150116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
150210eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh    }
150310eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
15049a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    private int getDeviceServiceChannelForUuid(String address,
15059a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            ParcelUuid uuid) {
15069a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        return getDeviceServiceChannelNative(getObjectPathFromAddress(address),
15079a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                uuid.toString(), 0x0004);
15089a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    }
15099a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
151024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    /**
151124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     * b is a handle to a Binder instance, so that this service can be notified
151224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     * for Applications that terminate unexpectedly, to clean there service
151324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     * records
151424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly     */
151524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    public synchronized int addRfcommServiceRecord(String serviceName, ParcelUuid uuid,
151624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            int channel, IBinder b) {
15178c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
15188c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh        if (!isEnabledInternal()) return -1;
15198c9dd7d8b99e1b064fc064a3c6737eaf179eae68Jaikumar Ganesh
152024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (serviceName == null || uuid == null || channel < 1 ||
152124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                channel > BluetoothSocket.MAX_RFCOMM_CHANNEL) {
152224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            return -1;
152324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
152424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (BluetoothUuid.isUuidPresent(BluetoothUuid.RESERVED_UUIDS, uuid)) {
152524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            Log.w(TAG, "Attempted to register a reserved UUID: " + uuid);
152624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            return -1;
152724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
152824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        int handle = addRfcommServiceRecordNative(serviceName,
152924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                uuid.getUuid().getMostSignificantBits(), uuid.getUuid().getLeastSignificantBits(),
153024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                (short)channel);
15319a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        if (DBG) Log.d(TAG, "new handle " + Integer.toHexString(handle));
153224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        if (handle == -1) {
153324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            return -1;
153424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
153524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
1536c980a495a6d357219a9e0860129ae6bb6d541843Jason Simmons        ServiceRecordClient client = new ServiceRecordClient();
1537c980a495a6d357219a9e0860129ae6bb6d541843Jason Simmons        client.pid = Binder.getCallingPid();
1538c980a495a6d357219a9e0860129ae6bb6d541843Jason Simmons        client.binder = b;
1539c980a495a6d357219a9e0860129ae6bb6d541843Jason Simmons        client.death = new Reaper(handle, client.pid, RFCOMM_RECORD_REAPER);
1540c980a495a6d357219a9e0860129ae6bb6d541843Jason Simmons        mServiceRecordToPid.put(new Integer(handle), client);
154124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        try {
1542c980a495a6d357219a9e0860129ae6bb6d541843Jason Simmons            b.linkToDeath(client.death, 0);
1543c980a495a6d357219a9e0860129ae6bb6d541843Jason Simmons        } catch (RemoteException e) {
1544c980a495a6d357219a9e0860129ae6bb6d541843Jason Simmons            Log.e(TAG, "", e);
1545c980a495a6d357219a9e0860129ae6bb6d541843Jason Simmons            client.death = null;
1546c980a495a6d357219a9e0860129ae6bb6d541843Jason Simmons        }
154724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        return handle;
154824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    }
154924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
155024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    public void removeServiceRecord(int handle) {
155124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
155224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly                                                "Need BLUETOOTH permission");
1553dcbc97fc28f4eb5910acc11dfac5efcd597c737dMatthew Xie        // Since this is a binder call check if Bluetooth is off
1554dcbc97fc28f4eb5910acc11dfac5efcd597c737dMatthew Xie        if (getBluetoothStateInternal() == BluetoothAdapter.STATE_OFF) return;
1555484867a8ed3d46fbb8df493c77f2e2d46a0db654Matthew Xie        Message message = mHandler.obtainMessage(MESSAGE_REMOVE_SERVICE_RECORD);
1556484867a8ed3d46fbb8df493c77f2e2d46a0db654Matthew Xie        message.obj = new Pair<Integer, Integer>(handle, Binder.getCallingPid());
1557484867a8ed3d46fbb8df493c77f2e2d46a0db654Matthew Xie        mHandler.sendMessage(message);
155824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    }
155924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
156024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private synchronized void checkAndRemoveRecord(int handle, int pid) {
1561c980a495a6d357219a9e0860129ae6bb6d541843Jason Simmons        ServiceRecordClient client = mServiceRecordToPid.get(handle);
1562c980a495a6d357219a9e0860129ae6bb6d541843Jason Simmons        if (client != null && pid == client.pid) {
15639a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            if (DBG) Log.d(TAG, "Removing service record " +
15649a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                Integer.toHexString(handle) + " for pid " + pid);
1565c980a495a6d357219a9e0860129ae6bb6d541843Jason Simmons
1566c980a495a6d357219a9e0860129ae6bb6d541843Jason Simmons            if (client.death != null) {
1567c980a495a6d357219a9e0860129ae6bb6d541843Jason Simmons                client.binder.unlinkToDeath(client.death, 0);
1568c980a495a6d357219a9e0860129ae6bb6d541843Jason Simmons            }
1569c980a495a6d357219a9e0860129ae6bb6d541843Jason Simmons
1570f1754050ceaadb4603aaaa0b1f0b193a305834afMatthew Xie            mServiceRecordToPid.remove(handle);
157124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            removeServiceRecordNative(handle);
157224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
157324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    }
157424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
157524bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private class Reaper implements IBinder.DeathRecipient {
1576ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh        int mPid;
1577ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh        int mHandle;
1578ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh        int mType;
1579ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh
1580ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh        Reaper(int handle, int pid, int type) {
1581ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh            mPid = pid;
1582ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh            mHandle = handle;
1583ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh            mType = type;
158424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
1585ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh
1586ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh        Reaper(int pid, int type) {
1587ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh            mPid = pid;
1588ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh            mType = type;
1589ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh        }
1590ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh
1591ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh        @Override
159224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        public void binderDied() {
159324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            synchronized (BluetoothService.this) {
1594ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                if (DBG) Log.d(TAG, "Tracked app " + mPid + " died" + "Type:" + mType);
1595ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                if (mType == RFCOMM_RECORD_REAPER) {
1596ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    checkAndRemoveRecord(mHandle, mPid);
1597ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                } else if (mType == STATE_CHANGE_REAPER) {
1598ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                    mStateChangeTracker.remove(mPid);
1599ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                }
1600ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh            }
1601ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh        }
1602ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh    }
1603ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh
1604ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh
1605ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh    @Override
1606ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh    public boolean changeApplicationBluetoothState(boolean on,
1607ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh            IBluetoothStateChangeCallback callback, IBinder binder) {
1608f5fb6c8ce36a98da47f32f4142d372bd5f650bfaJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
1609f5fb6c8ce36a98da47f32f4142d372bd5f650bfaJaikumar Ganesh
1610ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh        int pid = Binder.getCallingPid();
1611ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh        //mStateChangeTracker is a synchronized map
1612ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh        if (!mStateChangeTracker.containsKey(pid)) {
1613ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh            if (on) {
1614ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                mStateChangeTracker.put(pid, callback);
1615ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh            } else {
1616ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                return false;
161724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            }
1618ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh        } else if (!on) {
1619ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh            mStateChangeTracker.remove(pid);
162024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
1621ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh
1622ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh        if (binder != null) {
1623ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh            try {
1624ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                binder.linkToDeath(new Reaper(pid, STATE_CHANGE_REAPER), 0);
1625ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh            } catch (RemoteException e) {
1626f1754050ceaadb4603aaaa0b1f0b193a305834afMatthew Xie                Log.e(TAG, "", e);
1627ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh                return false;
1628ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh            }
1629ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh        }
1630ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh
1631ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh        int type;
1632ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh        if (on) {
1633ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh            type = BluetoothAdapterStateMachine.PER_PROCESS_TURN_ON;
1634ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh        } else {
1635ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh            type = BluetoothAdapterStateMachine.PER_PROCESS_TURN_OFF;
1636ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh        }
1637ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh
1638ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh        mBluetoothState.sendMessage(type, callback);
1639ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh        return true;
1640ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh    }
1641ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh
1642ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh    boolean isApplicationStateChangeTrackerEmpty() {
1643ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh        return mStateChangeTracker.isEmpty();
1644ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh    }
1645ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh
1646ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh    void clearApplicationStateChangeTracker() {
1647ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh        mStateChangeTracker.clear();
1648ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh    }
1649ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh
1650ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh    Collection<IBluetoothStateChangeCallback> getApplicationStateChangeCallbacks() {
1651ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh        return mStateChangeTracker.values();
1652ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh    }
1653ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh
1654ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh    int getNumberOfApplicationStateChangeTrackers() {
1655ef2cb7c93a99096799d415e721dda46d1bf7a005Jaikumar Ganesh        return mStateChangeTracker.size();
165624bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    }
165724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
16589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
16599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
16609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onReceive(Context context, Intent intent) {
16616e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh            if (intent == null) return;
16626e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh
16639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String action = intent.getAction();
16649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
16659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ContentResolver resolver = context.getContentResolver();
16669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Query the airplane mode from Settings.System just to make sure that
16679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // some random app is not sending this intent and disabling bluetooth
16687f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                if (isAirplaneModeOn()) {
16697f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    mBluetoothState.sendMessage(BluetoothAdapterStateMachine.AIRPLANE_MODE_ON);
16707f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                } else {
16717f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                    mBluetoothState.sendMessage(BluetoothAdapterStateMachine.AIRPLANE_MODE_OFF);
16729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
16736e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh            } else if (Intent.ACTION_DOCK_EVENT.equals(action)) {
16746e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                int state = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
16756e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                        Intent.EXTRA_DOCK_STATE_UNDOCKED);
16766e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                if (DBG) Log.v(TAG, "Received ACTION_DOCK_EVENT with State:" + state);
16776e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                if (state == Intent.EXTRA_DOCK_STATE_UNDOCKED) {
16786e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                    mDockAddress = null;
16796e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                    mDockPin = null;
16806e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                } else {
16816e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                    SharedPreferences.Editor editor =
16826e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                        mContext.getSharedPreferences(SHARED_PREFERENCES_NAME,
16836e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                                mContext.MODE_PRIVATE).edit();
16846e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                    editor.putBoolean(SHARED_PREFERENCE_DOCK_ADDRESS + mDockAddress, true);
168566fce5068a8a3aeb28aaf713843891b286a75280Brad Fitzpatrick                    editor.apply();
16866e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh                }
16879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
16889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
16899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
16909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16916e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh    private void registerForAirplaneMode(IntentFilter filter) {
169244303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        final ContentResolver resolver = mContext.getContentResolver();
169344303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        final String airplaneModeRadios = Settings.System.getString(resolver,
16949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Settings.System.AIRPLANE_MODE_RADIOS);
169544303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        final String toggleableRadios = Settings.System.getString(resolver,
169644303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey                Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
169744303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey
169844303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        mIsAirplaneSensitive = airplaneModeRadios == null ? true :
169944303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey                airplaneModeRadios.contains(Settings.System.RADIO_BLUETOOTH);
170044303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        mIsAirplaneToggleable = toggleableRadios == null ? false :
170144303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey                toggleableRadios.contains(Settings.System.RADIO_BLUETOOTH);
170244303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey
17039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mIsAirplaneSensitive) {
17046e9c443460e40e9d663c117ba836585335e7c2c1Jaikumar Ganesh            filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
17059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
17069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
17079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* Returns true if airplane mode is currently on */
1709f3171fb60c840a9bc0220fad651338346dddfff7Matthew Xie    /*package*/ final boolean isAirplaneModeOn() {
17109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return Settings.System.getInt(mContext.getContentResolver(),
17119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Settings.System.AIRPLANE_MODE_ON, 0) == 1;
17129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
17139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17141caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    /* Broadcast the Uuid intent */
17151caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    /*package*/ synchronized void sendUuidIntent(String address) {
17166179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh        ParcelUuid[] uuid = getUuidFromCache(address);
17176179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh        Intent intent = new Intent(BluetoothDevice.ACTION_UUID);
17182d3b98d868cda30535505b2a2fba47aa1c9c052bJaikumar Ganesh        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
17196179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh        intent.putExtra(BluetoothDevice.EXTRA_UUID, uuid);
17206179965e85ec17b836084a4a3d7963d8a7a1e1ccJaikumar Ganesh        mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
17219a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        mUuidIntentTracker.remove(address);
172216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    }
172316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
172416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    /*package*/ synchronized void makeServiceChannelCallbacks(String address) {
172516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        for (Iterator<RemoteService> iter = mUuidCallbackTracker.keySet().iterator();
172616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                iter.hasNext();) {
172716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            RemoteService service = iter.next();
172816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            if (service.address.equals(address)) {
17299a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                if (DBG) Log.d(TAG, "Cleaning up failed UUID channel lookup: "
17309a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                    + service.address + " " + service.uuid);
173116fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                IBluetoothCallback callback = mUuidCallbackTracker.get(service);
173216fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                if (callback != null) {
173316fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    try {
173416fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                        callback.onRfcommChannelFound(-1);
173516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                    } catch (RemoteException e) {Log.e(TAG, "", e);}
173616fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                }
173716fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly
173816fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly                iter.remove();
173916fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly            }
174016fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly        }
17411caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    }
17421caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh
17439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
17449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
17457f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        if (getBluetoothStateInternal() != BluetoothAdapter.STATE_ON) {
1746105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            return;
1747105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
1748105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
174924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("mIsAirplaneSensitive = " + mIsAirplaneSensitive);
175044303922f14ac71b446a6e50e1180be4c8fed2c7Jeff Sharkey        pw.println("mIsAirplaneToggleable = " + mIsAirplaneToggleable);
175124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly
175224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("Local address = " + getAddress());
175324bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("Local name = " + getName());
175424bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        pw.println("isDiscovering() = " + isDiscovering());
1755105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
175696a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh        mAdapter.getProfileProxy(mContext,
175796a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh                                 mBluetoothProfileServiceListener, BluetoothProfile.HEADSET);
17584ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh        mAdapter.getProfileProxy(mContext,
17594ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                mBluetoothProfileServiceListener, BluetoothProfile.INPUT_DEVICE);
176074ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh        mAdapter.getProfileProxy(mContext,
176174ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                mBluetoothProfileServiceListener, BluetoothProfile.PAN);
1762105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project
17639a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        dumpKnownDevices(pw);
17649a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        dumpAclConnectedDevices(pw);
17659a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        dumpHeadsetService(pw);
17664ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh        dumpInputDeviceProfile(pw);
176774ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh        dumpPanProfile(pw);
17689a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        dumpApplicationServiceRecords(pw);
1769cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh        dumpProfileState(pw);
1770cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh    }
1771cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh
1772cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh    private void dumpProfileState(PrintWriter pw) {
1773cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh        pw.println("\n--Profile State dump--");
1774cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh        pw.println("\n Headset profile state:" +
1775cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh                mAdapter.getProfileConnectionState(BluetoothProfile.HEADSET));
1776cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh        pw.println("\n A2dp profile state:" +
1777cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh                mAdapter.getProfileConnectionState(BluetoothProfile.A2DP));
1778cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh        pw.println("\n HID profile state:" +
1779cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh                mAdapter.getProfileConnectionState(BluetoothProfile.INPUT_DEVICE));
1780cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh        pw.println("\n PAN profile state:" +
1781cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh                mAdapter.getProfileConnectionState(BluetoothProfile.PAN));
17824ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh    }
17834ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh
17849a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    private void dumpHeadsetService(PrintWriter pw) {
1785105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        pw.println("\n--Headset Service--");
178698f06da8ed2851a768358de1979838ad1bb6d187Matthew Xie        if (mHeadsetProxy != null) {
178798f06da8ed2851a768358de1979838ad1bb6d187Matthew Xie            List<BluetoothDevice> deviceList = mHeadsetProxy.getConnectedDevices();
1788bb0773fac888c6748cbf778ab5c99c7d0a2c1309Jaikumar Ganesh            if (deviceList.size() == 0) {
178974ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                pw.println("No headsets connected");
1790bb0773fac888c6748cbf778ab5c99c7d0a2c1309Jaikumar Ganesh            } else {
1791bb0773fac888c6748cbf778ab5c99c7d0a2c1309Jaikumar Ganesh                BluetoothDevice device = deviceList.get(0);
17929a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                pw.println("\ngetConnectedDevices[0] = " + device);
17939a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                dumpHeadsetConnectionState(pw, device);
1794bb0773fac888c6748cbf778ab5c99c7d0a2c1309Jaikumar Ganesh                pw.println("getBatteryUsageHint() = " +
179598f06da8ed2851a768358de1979838ad1bb6d187Matthew Xie                             mHeadsetProxy.getBatteryUsageHint(device));
179696a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh            }
179796a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh
17985a1e4cf83f5be1b5d79e2643fa791aa269b6a4bcJaikumar Ganesh            deviceList.clear();
179998f06da8ed2851a768358de1979838ad1bb6d187Matthew Xie            deviceList = mHeadsetProxy.getDevicesMatchingConnectionStates(new int[] {
180096a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh                     BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED});
180174ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            pw.println("--Connected and Disconnected Headsets");
1802bb0773fac888c6748cbf778ab5c99c7d0a2c1309Jaikumar Ganesh            for (BluetoothDevice device: deviceList) {
180396a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh                pw.println(device);
180498f06da8ed2851a768358de1979838ad1bb6d187Matthew Xie                if (mHeadsetProxy.isAudioConnected(device)) {
180596a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh                    pw.println("SCO audio connected to device:" + device);
180696a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh                }
180796a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh            }
1808105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        }
18094ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh    }
18106c901db72dbaf57d8fdf26adae6721de14ecae22Nick Pelly
18114ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh    private void dumpInputDeviceProfile(PrintWriter pw) {
18124ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh        pw.println("\n--Bluetooth Service- Input Device Profile");
18134ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh        if (mInputDevice != null) {
18144ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            List<BluetoothDevice> deviceList = mInputDevice.getConnectedDevices();
18154ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            if (deviceList.size() == 0) {
181674ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                pw.println("No input devices connected");
18174ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            } else {
181874ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                pw.println("Number of connected devices:" + deviceList.size());
18194ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                BluetoothDevice device = deviceList.get(0);
18204ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                pw.println("getConnectedDevices[0] = " + device);
18214ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                pw.println("Priority of Connected device = " + mInputDevice.getPriority(device));
18224ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh
18234ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                switch (mInputDevice.getConnectionState(device)) {
18244ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                    case BluetoothInputDevice.STATE_CONNECTING:
18254ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                        pw.println("getConnectionState() = STATE_CONNECTING");
18264ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                        break;
18274ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                    case BluetoothInputDevice.STATE_CONNECTED:
18284ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                        pw.println("getConnectionState() = STATE_CONNECTED");
18294ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                        break;
18304ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                    case BluetoothInputDevice.STATE_DISCONNECTING:
18314ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                        pw.println("getConnectionState() = STATE_DISCONNECTING");
18324ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                        break;
18334ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                }
18344ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            }
18354ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            deviceList.clear();
18364ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            deviceList = mInputDevice.getDevicesMatchingConnectionStates(new int[] {
18374ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                     BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED});
18384ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            pw.println("--Connected and Disconnected input devices");
18394ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            for (BluetoothDevice device: deviceList) {
18404ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                pw.println(device);
18414ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            }
184224bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly        }
18439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
18449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
184574ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh    private void dumpPanProfile(PrintWriter pw) {
184674ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh        pw.println("\n--Bluetooth Service- Pan Profile");
184774ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh        if (mPan != null) {
184874ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            List<BluetoothDevice> deviceList = mPan.getConnectedDevices();
184974ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            if (deviceList.size() == 0) {
185074ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                pw.println("No Pan devices connected");
185174ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            } else {
185274ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                pw.println("Number of connected devices:" + deviceList.size());
185374ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                BluetoothDevice device = deviceList.get(0);
185474ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                pw.println("getConnectedDevices[0] = " + device);
185574ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh
185674ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                switch (mPan.getConnectionState(device)) {
185774ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                    case BluetoothInputDevice.STATE_CONNECTING:
185874ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                        pw.println("getConnectionState() = STATE_CONNECTING");
185974ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                        break;
186074ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                    case BluetoothInputDevice.STATE_CONNECTED:
186174ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                        pw.println("getConnectionState() = STATE_CONNECTED");
186274ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                        break;
186374ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                    case BluetoothInputDevice.STATE_DISCONNECTING:
186474ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                        pw.println("getConnectionState() = STATE_DISCONNECTING");
186574ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                        break;
186674ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                }
186774ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            }
186874ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            deviceList.clear();
186974ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            deviceList = mPan.getDevicesMatchingConnectionStates(new int[] {
187074ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                     BluetoothProfile.STATE_CONNECTED, BluetoothProfile.STATE_DISCONNECTED});
187174ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            pw.println("--Connected and Disconnected Pan devices");
187274ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            for (BluetoothDevice device: deviceList) {
187374ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                pw.println(device);
187474ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            }
187574ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh        }
18769a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    }
18779a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
18789a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    private void dumpHeadsetConnectionState(PrintWriter pw,
18799a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            BluetoothDevice device) {
188098f06da8ed2851a768358de1979838ad1bb6d187Matthew Xie        switch (mHeadsetProxy.getConnectionState(device)) {
18819a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            case BluetoothHeadset.STATE_CONNECTING:
18829a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                pw.println("getConnectionState() = STATE_CONNECTING");
18839a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                break;
18849a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            case BluetoothHeadset.STATE_CONNECTED:
18859a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                pw.println("getConnectionState() = STATE_CONNECTED");
18869a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                break;
18879a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            case BluetoothHeadset.STATE_DISCONNECTING:
18889a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                pw.println("getConnectionState() = STATE_DISCONNECTING");
18899a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                break;
18909a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            case BluetoothHeadset.STATE_AUDIO_CONNECTED:
18919a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                pw.println("getConnectionState() = STATE_AUDIO_CONNECTED");
18929a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                break;
18939a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        }
18949a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    }
18959a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
18969a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    private void dumpApplicationServiceRecords(PrintWriter pw) {
18979a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        pw.println("\n--Application Service Records--");
18989a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        for (Integer handle : mServiceRecordToPid.keySet()) {
1899c980a495a6d357219a9e0860129ae6bb6d541843Jason Simmons            Integer pid = mServiceRecordToPid.get(handle).pid;
19009a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            pw.println("\tpid " + pid + " handle " + Integer.toHexString(handle));
19019a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        }
190274ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh    }
190374ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh
19049a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    private void dumpAclConnectedDevices(PrintWriter pw) {
19059a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        String[] devicesObjectPath = getKnownDevices();
19069a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        pw.println("\n--ACL connected devices--");
19079a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        if (devicesObjectPath != null) {
19089a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            for (String device : devicesObjectPath) {
19099a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                pw.println(getAddressFromObjectPath(device));
19109a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            }
19119a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        }
19129a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    }
19139a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
19149a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    private void dumpKnownDevices(PrintWriter pw) {
19159a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        pw.println("\n--Known devices--");
19169a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        for (String address : mDeviceProperties.keySet()) {
19179a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            int bondState = mBondState.getBondState(address);
19189a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            pw.printf("%s %10s (%d) %s\n", address,
19199a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                       toBondStateString(bondState),
19209a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                       mBondState.getAttempt(address),
19219a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                       getRemoteName(address));
19229a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
19239a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            Map<ParcelUuid, Integer> uuidChannels = mDeviceServiceChannelCache.get(address);
19249a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            if (uuidChannels == null) {
19259a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                pw.println("\tuuids = null");
19269a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            } else {
19279a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                for (ParcelUuid uuid : uuidChannels.keySet()) {
19289a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                    Integer channel = uuidChannels.get(uuid);
19299a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                    if (channel == null) {
19309a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                        pw.println("\t" + uuid);
19319a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                    } else {
19329a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                        pw.println("\t" + uuid + " RFCOMM channel = " + channel);
19339a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                    }
19349a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                }
19359a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            }
19369a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            for (RemoteService service : mUuidCallbackTracker.keySet()) {
19379a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                if (service.address.equals(address)) {
19389a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                    pw.println("\tPENDING CALLBACK: " + service.uuid);
19399a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                }
19409a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            }
19419a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        }
19429a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    }
19439a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
194498f06da8ed2851a768358de1979838ad1bb6d187Matthew Xie    private void getProfileProxy() {
194598f06da8ed2851a768358de1979838ad1bb6d187Matthew Xie        mAdapter.getProfileProxy(mContext,
194698f06da8ed2851a768358de1979838ad1bb6d187Matthew Xie                                 mBluetoothProfileServiceListener, BluetoothProfile.HEADSET);
194798f06da8ed2851a768358de1979838ad1bb6d187Matthew Xie    }
194898f06da8ed2851a768358de1979838ad1bb6d187Matthew Xie
194996a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh    private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
195096a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh        new BluetoothProfile.ServiceListener() {
195196a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh        public void onServiceConnected(int profile, BluetoothProfile proxy) {
19524ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            if (profile == BluetoothProfile.HEADSET) {
195398f06da8ed2851a768358de1979838ad1bb6d187Matthew Xie                mHeadsetProxy = (BluetoothHeadset) proxy;
19544ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            } else if (profile == BluetoothProfile.INPUT_DEVICE) {
19554ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                mInputDevice = (BluetoothInputDevice) proxy;
195674ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            } else if (profile == BluetoothProfile.PAN) {
195774ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                mPan = (BluetoothPan) proxy;
19584ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            }
19594ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh        }
196096a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh        public void onServiceDisconnected(int profile) {
19614ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            if (profile == BluetoothProfile.HEADSET) {
196298f06da8ed2851a768358de1979838ad1bb6d187Matthew Xie                mHeadsetProxy = null;
19634ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            } else if (profile == BluetoothProfile.INPUT_DEVICE) {
19644ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh                mInputDevice = null;
196574ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            } else if (profile == BluetoothProfile.PAN) {
196674ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh                mPan = null;
19674ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            }
196896a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh        }
196996a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh    };
197096a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh
1971d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /* package */ static int bluezStringToScanMode(boolean pairable, boolean discoverable) {
1972d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (pairable && discoverable)
1973bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            return BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE;
1974d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        else if (pairable && !discoverable)
1975bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            return BluetoothAdapter.SCAN_MODE_CONNECTABLE;
1976d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        else
1977bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly            return BluetoothAdapter.SCAN_MODE_NONE;
19789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
19799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* package */ static String scanModeToBluezString(int mode) {
19819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        switch (mode) {
1982bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        case BluetoothAdapter.SCAN_MODE_NONE:
19839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "off";
1984bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
19859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "connectable";
1986bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pelly        case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
19879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "discoverable";
19889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
19899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return null;
19909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
19919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1992d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /*package*/ String getAddressFromObjectPath(String objectPath) {
19939a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        String adapterObjectPath = mAdapterProperties.getObjectPath();
1994d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (adapterObjectPath == null || objectPath == null) {
1995f51eadaf1f83abfe16a609a4ded6d789494689b2Jake Hamby            Log.e(TAG, "getAddressFromObjectPath: AdapterObjectPath:" + adapterObjectPath +
1996d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                    "  or deviceObjectPath:" + objectPath + " is null");
1997d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return null;
1998d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
1999d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (!objectPath.startsWith(adapterObjectPath)) {
2000f51eadaf1f83abfe16a609a4ded6d789494689b2Jake Hamby            Log.e(TAG, "getAddressFromObjectPath: AdapterObjectPath:" + adapterObjectPath +
2001d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                    "  is not a prefix of deviceObjectPath:" + objectPath +
2002d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh                    "bluetoothd crashed ?");
2003d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return null;
2004d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
2005d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        String address = objectPath.substring(adapterObjectPath.length());
2006d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (address != null) return address.replace('_', ':');
2007d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
2008d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        Log.e(TAG, "getAddressFromObjectPath: Address being returned is null");
2009d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return null;
2010d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
2011d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
2012d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    /*package*/ String getObjectPathFromAddress(String address) {
20139a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        String path = mAdapterProperties.getObjectPath();
2014d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        if (path == null) {
2015d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            Log.e(TAG, "Error: Object Path is null");
2016d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            return null;
2017d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        }
2018d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        path = path + address.replace(":", "_");
2019d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh        return path;
2020d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    }
2021d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
2022b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh    /*package */ void setLinkTimeout(String address, int num_slots) {
2023b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh        String path = getObjectPathFromAddress(address);
2024b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh        boolean result = setLinkTimeoutNative(path, num_slots);
2025b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh
20269a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        if (!result) Log.d(TAG, "Set Link Timeout to " + num_slots + " slots failed");
2027b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh    }
2028b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh
202930b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    /**** Handlers for PAN  Profile ****/
20306003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh    // TODO: This needs to be converted to a state machine.
203130b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
20326003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh    public boolean isTetheringOn() {
203330b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
20346003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        synchronized (mBluetoothPanProfileHandler) {
20356003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh            return mBluetoothPanProfileHandler.isTetheringOn();
20366003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        }
203730b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
203830b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
20396003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh    /*package*/boolean allowIncomingTethering() {
20406003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        synchronized (mBluetoothPanProfileHandler) {
20416003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh            return mBluetoothPanProfileHandler.allowIncomingTethering();
20426003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        }
204330b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
204430b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
20456003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh    public void setBluetoothTethering(boolean value) {
204630b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
20476003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        synchronized (mBluetoothPanProfileHandler) {
20486003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh            mBluetoothPanProfileHandler.setBluetoothTethering(value);
20496003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        }
205030b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
205130b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
20526003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh    public int getPanDeviceConnectionState(BluetoothDevice device) {
205330b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
20546003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        synchronized (mBluetoothPanProfileHandler) {
20556003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh            return mBluetoothPanProfileHandler.getPanDeviceConnectionState(device);
20566003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        }
205730b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
205830b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
20596003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh    public boolean connectPanDevice(BluetoothDevice device) {
206030b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
206130b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh            "Need BLUETOOTH_ADMIN permission");
20626003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        synchronized (mBluetoothPanProfileHandler) {
20636003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh            return mBluetoothPanProfileHandler.connectPanDevice(device);
20646003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        }
206530b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
206630b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
20676003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh    public List<BluetoothDevice> getConnectedPanDevices() {
206830b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
20696003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        synchronized (mBluetoothPanProfileHandler) {
20706003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh            return mBluetoothPanProfileHandler.getConnectedPanDevices();
20716003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        }
207230b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
207330b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
20746003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh    public List<BluetoothDevice> getPanDevicesMatchingConnectionStates(
207574ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh            int[] states) {
207674ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
20776003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        synchronized (mBluetoothPanProfileHandler) {
20786003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh            return mBluetoothPanProfileHandler.getPanDevicesMatchingConnectionStates(states);
20796003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        }
208074ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh    }
208174ef1199459629c5dd9f272f8cd706d82cdfeeb1Jaikumar Ganesh
20826003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh    public boolean disconnectPanDevice(BluetoothDevice device) {
208330b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
208430b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh            "Need BLUETOOTH_ADMIN permission");
20856003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        synchronized (mBluetoothPanProfileHandler) {
20866003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh            return mBluetoothPanProfileHandler.disconnectPanDevice(device);
20876003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        }
208830b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
208930b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
20906003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh    /*package*/void handlePanDeviceStateChange(BluetoothDevice device,
209130b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh                                                             String iface,
209230b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh                                                             int state,
209330b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh                                                             int role) {
20946003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        synchronized (mBluetoothPanProfileHandler) {
20956003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh            mBluetoothPanProfileHandler.handlePanDeviceStateChange(device, iface, state, role);
20966003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        }
209730b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
209830b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
20996003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh    /*package*/void handlePanDeviceStateChange(BluetoothDevice device,
210030b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh                                                             int state, int role) {
21016003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        synchronized (mBluetoothPanProfileHandler) {
21026003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh            mBluetoothPanProfileHandler.handlePanDeviceStateChange(device, null, state, role);
21036003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        }
210430b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
210530b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
210630b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    /**** Handlers for Input Device Profile ****/
21076003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh    // This needs to be converted to state machine
210830b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
21096003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh    public boolean connectInputDevice(BluetoothDevice device) {
211030b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
211130b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh                                                "Need BLUETOOTH_ADMIN permission");
211230b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        BluetoothDeviceProfileState state = mDeviceProfileState.get(device.getAddress());
21136003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        synchronized (mBluetoothInputProfileHandler) {
21146003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh            return mBluetoothInputProfileHandler.connectInputDevice(device, state);
21156003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        }
211630b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
211730b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
21186003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh    public boolean connectInputDeviceInternal(BluetoothDevice device) {
21196003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        synchronized (mBluetoothInputProfileHandler) {
21206003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh            return mBluetoothInputProfileHandler.connectInputDeviceInternal(device);
21216003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        }
212230b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
212330b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
21246003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh    public boolean disconnectInputDevice(BluetoothDevice device) {
212530b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
212630b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh                                                "Need BLUETOOTH_ADMIN permission");
212730b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        BluetoothDeviceProfileState state = mDeviceProfileState.get(device.getAddress());
21286003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        synchronized (mBluetoothInputProfileHandler) {
21296003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh            return mBluetoothInputProfileHandler.disconnectInputDevice(device, state);
21306003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        }
213130b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
213230b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
21336003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh    public boolean disconnectInputDeviceInternal(BluetoothDevice device) {
21346003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        synchronized (mBluetoothInputProfileHandler) {
21356003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh            return mBluetoothInputProfileHandler.disconnectInputDeviceInternal(device);
21366003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        }
213730b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
213830b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
21396003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh    public int getInputDeviceConnectionState(BluetoothDevice device) {
214030b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
21416003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        synchronized (mBluetoothInputProfileHandler) {
21426003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh            return mBluetoothInputProfileHandler.getInputDeviceConnectionState(device);
21436003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        }
214430b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
214530b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
21466003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh    public List<BluetoothDevice> getConnectedInputDevices() {
214730b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
21486003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        synchronized (mBluetoothInputProfileHandler) {
21496003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh            return mBluetoothInputProfileHandler.getConnectedInputDevices();
21506003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        }
215130b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
215230b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
21536003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh    public List<BluetoothDevice> getInputDevicesMatchingConnectionStates(
21544ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh            int[] states) {
21554ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
21566003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        synchronized (mBluetoothInputProfileHandler) {
21576003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh            return mBluetoothInputProfileHandler.getInputDevicesMatchingConnectionStates(states);
21586003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        }
21594ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh    }
21604ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh
21614ab0e7746fe74a9e4d75d374f73b7af87420b2f6Jaikumar Ganesh
21626003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh    public int getInputDevicePriority(BluetoothDevice device) {
216330b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
21646003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        synchronized (mBluetoothInputProfileHandler) {
21656003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh            return mBluetoothInputProfileHandler.getInputDevicePriority(device);
21666003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        }
216730b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
216830b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
21696003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh    public boolean setInputDevicePriority(BluetoothDevice device, int priority) {
217030b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
217130b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh                                                "Need BLUETOOTH_ADMIN permission");
21726003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        synchronized (mBluetoothInputProfileHandler) {
21736003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh            return mBluetoothInputProfileHandler.setInputDevicePriority(device, priority);
21746003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        }
217530b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
217630b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
2177bbd86750570ff75e428b3810dc2e65db558c14b2Jaikumar Ganesh    /**
2178bbd86750570ff75e428b3810dc2e65db558c14b2Jaikumar Ganesh     * Handle incoming profile acceptance for profiles handled by Bluetooth Service,
2179bbd86750570ff75e428b3810dc2e65db558c14b2Jaikumar Ganesh     * currently PAN and HID. This also is the catch all for all rejections for profiles
2180bbd86750570ff75e428b3810dc2e65db558c14b2Jaikumar Ganesh     * that is not supported.
2181bbd86750570ff75e428b3810dc2e65db558c14b2Jaikumar Ganesh     *
2182bbd86750570ff75e428b3810dc2e65db558c14b2Jaikumar Ganesh     * @param device - Bluetooth Device
2183bbd86750570ff75e428b3810dc2e65db558c14b2Jaikumar Ganesh     * @param allow - true / false
2184bbd86750570ff75e428b3810dc2e65db558c14b2Jaikumar Ganesh     * @return
2185bbd86750570ff75e428b3810dc2e65db558c14b2Jaikumar Ganesh     */
2186bbd86750570ff75e428b3810dc2e65db558c14b2Jaikumar Ganesh    public boolean allowIncomingProfileConnect(BluetoothDevice device, boolean allow) {
2187a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
2188a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                                                "Need BLUETOOTH_ADMIN permission");
2189a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        String address = device.getAddress();
2190a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
2191a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            return false;
2192a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        }
2193a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie
2194a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        Integer data = getAuthorizationAgentRequestData(address);
2195a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        if (data == null) {
2196bbd86750570ff75e428b3810dc2e65db558c14b2Jaikumar Ganesh            Log.w(TAG, "allowIncomingProfileConnect(" + device +
2197a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                  ") called but no native data available");
2198a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            return false;
2199a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        }
2200bbd86750570ff75e428b3810dc2e65db558c14b2Jaikumar Ganesh        if (DBG) log("allowIncomingProfileConnect: " + device + " : " + allow + " : " + data);
2201a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        return setAuthorizationNative(address, allow, data.intValue());
2202a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    }
2203a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie
22046003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh    /*package*/List<BluetoothDevice> lookupInputDevicesMatchingStates(int[] states) {
22056003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        synchronized (mBluetoothInputProfileHandler) {
22066003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh            return mBluetoothInputProfileHandler.lookupInputDevicesMatchingStates(states);
22076003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        }
220830b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
220930b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
22106003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh    /*package*/void handleInputDevicePropertyChange(String address, boolean connected) {
22116003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        synchronized (mBluetoothInputProfileHandler) {
22126003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh            mBluetoothInputProfileHandler.handleInputDevicePropertyChange(address, connected);
22136003fe9af08b134485ebac61ee312528325f6c3cJaikumar Ganesh        }
221430b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    }
221530b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh
22162ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /**** Handlers for Health Device Profile ****/
22172ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    // TODO: All these need to be converted to a state machine.
22182ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
2219fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh    public boolean registerAppConfiguration(BluetoothHealthAppConfiguration config,
2220fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh                                            IBluetoothHealthCallback callback) {
22212ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
22222ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                "Need BLUETOOTH permission");
22232ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        synchronized (mBluetoothHealthProfileHandler) {
2224fb658c72a3a76dac334c39070d1501a2575c1069Jaikumar Ganesh                return mBluetoothHealthProfileHandler.registerAppConfiguration(config, callback);
22252ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        }
22262ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
22272ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
22282ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public boolean unregisterAppConfiguration(BluetoothHealthAppConfiguration config) {
22292ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
22302ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                "Need BLUETOOTH permission");
22312ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        synchronized (mBluetoothHealthProfileHandler) {
22322ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                return mBluetoothHealthProfileHandler.unregisterAppConfiguration(config);
22332ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        }
22342ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
22352ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
22362ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
22372ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public boolean connectChannelToSource(BluetoothDevice device,
22382ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            BluetoothHealthAppConfiguration config) {
22392ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
22402ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                "Need BLUETOOTH permission");
22412ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        synchronized (mBluetoothHealthProfileHandler) {
22422ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            return mBluetoothHealthProfileHandler.connectChannelToSource(device,
22432ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                    config);
22442ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        }
22452ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
22462ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
22472ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public boolean connectChannelToSink(BluetoothDevice device,
22482ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            BluetoothHealthAppConfiguration config, int channelType) {
22492ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
22502ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                                                "Need BLUETOOTH permission");
22512ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        synchronized (mBluetoothHealthProfileHandler) {
22522ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            return mBluetoothHealthProfileHandler.connectChannel(device, config,
22532ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                    channelType);
22542ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        }
22552ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
22562ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
22572ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public boolean disconnectChannel(BluetoothDevice device,
2258eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh            BluetoothHealthAppConfiguration config, int id) {
22592ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
22602ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                "Need BLUETOOTH permission");
22612ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        synchronized (mBluetoothHealthProfileHandler) {
2262eb9d34630f74d0260690287f2df57c0cd3d7ba1dJaikumar Ganesh            return mBluetoothHealthProfileHandler.disconnectChannel(device, config, id);
22632ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        }
22642ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
22652ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
22662ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public ParcelFileDescriptor getMainChannelFd(BluetoothDevice device,
22672ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            BluetoothHealthAppConfiguration config) {
22682ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
22692ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                "Need BLUETOOTH permission");
22702ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        synchronized (mBluetoothHealthProfileHandler) {
22712ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            return mBluetoothHealthProfileHandler.getMainChannelFd(device, config);
22722ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        }
22732ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
22742ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
22752ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /*package*/ void onHealthDevicePropertyChanged(String devicePath,
22762ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            String channelPath) {
22772ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        synchronized (mBluetoothHealthProfileHandler) {
22782ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            mBluetoothHealthProfileHandler.onHealthDevicePropertyChanged(devicePath,
22792ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                    channelPath);
22802ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        }
22812ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
22822ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
22832ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    /*package*/ void onHealthDeviceChannelChanged(String devicePath,
22842ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            String channelPath, boolean exists) {
22852ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        synchronized(mBluetoothHealthProfileHandler) {
22862ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            mBluetoothHealthProfileHandler.onHealthDeviceChannelChanged(devicePath,
22872ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                    channelPath, exists);
22882ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        }
22892ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
22902ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
2291b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh    /*package*/ void onHealthDeviceChannelConnectionError(int channelCode,
2292b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh            int newState) {
2293b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh        synchronized(mBluetoothHealthProfileHandler) {
2294b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh            mBluetoothHealthProfileHandler.onHealthDeviceChannelConnectionError(channelCode,
2295b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh                                                                                newState);
2296b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh        }
2297b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh    }
2298b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh
22992ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public int getHealthDeviceConnectionState(BluetoothDevice device) {
23002ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
23012ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                "Need BLUETOOTH permission");
23022ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        synchronized (mBluetoothHealthProfileHandler) {
23032ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            return mBluetoothHealthProfileHandler.getHealthDeviceConnectionState(device);
23042ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        }
23052ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
23062ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
23072ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public List<BluetoothDevice> getConnectedHealthDevices() {
23082ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
23092ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                "Need BLUETOOTH permission");
23102ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        synchronized (mBluetoothHealthProfileHandler) {
23112ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            return mBluetoothHealthProfileHandler.getConnectedHealthDevices();
23122ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        }
23132ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
23142ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
23152ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    public List<BluetoothDevice> getHealthDevicesMatchingConnectionStates(
23162ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            int[] states) {
23172ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
23182ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                "Need BLUETOOTH permission");
23192ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        synchronized (mBluetoothHealthProfileHandler) {
23202ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            return mBluetoothHealthProfileHandler.
23212ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh                    getHealthDevicesMatchingConnectionStates(states);
23222ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh        }
23232ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    }
23242ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
2325a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    /*package*/boolean notifyIncomingHidConnection(String address) {
2326a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
2327a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        if (state == null) {
2328a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            return false;
2329a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        }
2330a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        Message msg = new Message();
2331a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        msg.what = BluetoothDeviceProfileState.CONNECT_HID_INCOMING;
2332a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        state.sendMessage(msg);
2333a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        return true;
2334a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    }
2335a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie
23369b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public boolean connectHeadset(String address) {
233796a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh        if (getBondState(address) != BluetoothDevice.BOND_BONDED) return false;
233896a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh
2339f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
23409b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (state != null) {
2341f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            Message msg = new Message();
2342f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.arg1 = BluetoothDeviceProfileState.CONNECT_HFP_OUTGOING;
2343f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.obj = state;
2344f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            mHfpProfileState.sendMessage(msg);
2345f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            return true;
23469b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
23479b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        return false;
23489b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
23499b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
23509b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public boolean disconnectHeadset(String address) {
235196a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh        if (getBondState(address) != BluetoothDevice.BOND_BONDED) return false;
235296a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh
2353f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
23549b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (state != null) {
2355f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            Message msg = new Message();
2356f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.arg1 = BluetoothDeviceProfileState.DISCONNECT_HFP_OUTGOING;
2357f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.obj = state;
2358f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            mHfpProfileState.sendMessage(msg);
23599b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            return true;
23609b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
23619b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        return false;
23629b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
23639b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
23649b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public boolean connectSink(String address) {
236596a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh        if (getBondState(address) != BluetoothDevice.BOND_BONDED) return false;
236696a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh
2367f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
23689b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (state != null) {
2369f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            Message msg = new Message();
2370f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.arg1 = BluetoothDeviceProfileState.CONNECT_A2DP_OUTGOING;
2371f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.obj = state;
2372f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            mA2dpProfileState.sendMessage(msg);
2373f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            return true;
23749b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
23759b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        return false;
23769b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
23779b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
23789b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    public boolean disconnectSink(String address) {
237996a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh        if (getBondState(address) != BluetoothDevice.BOND_BONDED) return false;
238096a79830ea1ae3ab3d6d3cce2bd1397fcd40ea0eJaikumar Ganesh
2381f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
23829b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (state != null) {
2383f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            Message msg = new Message();
2384f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.arg1 = BluetoothDeviceProfileState.DISCONNECT_A2DP_OUTGOING;
2385f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            msg.obj = state;
2386f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh            mA2dpProfileState.sendMessage(msg);
23879b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            return true;
23889b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
23899b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        return false;
23909b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
23919b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
2392d3728cb32fbd0a85bc77f4bcbdfea386ede2c75fJaikumar Ganesh    BluetoothDeviceProfileState addProfileState(String address, boolean setTrust) {
23939bb275197df8eb999eab4cdd0a2aff83c2bb2ef6Jaikumar Ganesh        BluetoothDeviceProfileState state =
23949bb275197df8eb999eab4cdd0a2aff83c2bb2ef6Jaikumar Ganesh            new BluetoothDeviceProfileState(mContext, address, this, mA2dpService, setTrust);
2395f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        mDeviceProfileState.put(address, state);
23969b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        state.start();
23979b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        return state;
23989b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
23999b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
24009a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    void removeProfileState(String address) {
24019bb275197df8eb999eab4cdd0a2aff83c2bb2ef6Jaikumar Ganesh        BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
24029bb275197df8eb999eab4cdd0a2aff83c2bb2ef6Jaikumar Ganesh        if (state == null) return;
24039bb275197df8eb999eab4cdd0a2aff83c2bb2ef6Jaikumar Ganesh
24049bb275197df8eb999eab4cdd0a2aff83c2bb2ef6Jaikumar Ganesh        state.quit();
2405f1048cdb68d4e4671be2060ca31a3adfc613e88eJaikumar Ganesh        mDeviceProfileState.remove(address);
24069b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
24079b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
240844b58ab89e59b3d8241901232c8f7dc9617b206eMatthew Xie    String[] getKnownDevices() {
24099a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        String[] bonds = null;
2410a66590ed78d0ec8e837dab80a4376a10d7023e9aJaikumar Ganesh        String val = getProperty("Devices", true);
24119a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        if (val != null) {
24129a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            bonds = val.split(",");
24139a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        }
24149a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        return bonds;
24159a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    }
24169a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
24179b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    private void initProfileState() {
24189a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        String[] bonds = null;
2419a66590ed78d0ec8e837dab80a4376a10d7023e9aJaikumar Ganesh        String val = getProperty("Devices", false);
24209b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (val != null) {
24219b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            bonds = val.split(",");
24229b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
24239b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (bonds == null) {
24249b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            return;
24259b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
24269b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        for (String path : bonds) {
24279b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            String address = getAddressFromObjectPath(path);
2428d3728cb32fbd0a85bc77f4bcbdfea386ede2c75fJaikumar Ganesh            BluetoothDeviceProfileState state = addProfileState(address, false);
24299a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        }
24309a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    }
24319a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
24329a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    private void autoConnect() {
24339a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        String[] bonds = getKnownDevices();
24349a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        if (bonds == null) {
24359a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            return;
24369a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        }
24379a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        for (String path : bonds) {
24389a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            String address = getAddressFromObjectPath(path);
24399a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
24409a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            if (state != null) {
24419a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                Message msg = new Message();
24429a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                msg.what = BluetoothDeviceProfileState.AUTO_CONNECT_PROFILES;
24439a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                state.sendMessage(msg);
24449a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            }
24459b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
24469b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
24479b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
244898f06da8ed2851a768358de1979838ad1bb6d187Matthew Xie    public boolean notifyIncomingConnection(String address, boolean rejected) {
244998f06da8ed2851a768358de1979838ad1bb6d187Matthew Xie        BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
24509b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        if (state != null) {
24519b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            Message msg = new Message();
245298f06da8ed2851a768358de1979838ad1bb6d187Matthew Xie            if (rejected) {
245398f06da8ed2851a768358de1979838ad1bb6d187Matthew Xie                if (mA2dpService.getPriority(getRemoteDevice(address)) >=
245498f06da8ed2851a768358de1979838ad1bb6d187Matthew Xie                    BluetoothProfile.PRIORITY_ON) {
245598f06da8ed2851a768358de1979838ad1bb6d187Matthew Xie                    msg.what = BluetoothDeviceProfileState.CONNECT_OTHER_PROFILES;
245698f06da8ed2851a768358de1979838ad1bb6d187Matthew Xie                    msg.arg1 = BluetoothDeviceProfileState.CONNECT_A2DP_OUTGOING;
245798f06da8ed2851a768358de1979838ad1bb6d187Matthew Xie                    state.sendMessageDelayed(msg,
245898f06da8ed2851a768358de1979838ad1bb6d187Matthew Xie                        BluetoothDeviceProfileState.CONNECT_OTHER_PROFILES_DELAY);
245998f06da8ed2851a768358de1979838ad1bb6d187Matthew Xie                }
246098f06da8ed2851a768358de1979838ad1bb6d187Matthew Xie            } else {
246198f06da8ed2851a768358de1979838ad1bb6d187Matthew Xie                msg.what = BluetoothDeviceProfileState.CONNECT_HFP_INCOMING;
246298f06da8ed2851a768358de1979838ad1bb6d187Matthew Xie                state.sendMessage(msg);
246398f06da8ed2851a768358de1979838ad1bb6d187Matthew Xie            }
24649b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh            return true;
24659b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        }
24669b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        return false;
24679b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
24689b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
246998f06da8ed2851a768358de1979838ad1bb6d187Matthew Xie    /*package*/ boolean notifyIncomingA2dpConnection(String address, boolean rejected) {
247098f06da8ed2851a768358de1979838ad1bb6d187Matthew Xie       BluetoothDeviceProfileState state = mDeviceProfileState.get(address);
24719b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh       if (state != null) {
24729b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh           Message msg = new Message();
247398f06da8ed2851a768358de1979838ad1bb6d187Matthew Xie           if (rejected) {
247498f06da8ed2851a768358de1979838ad1bb6d187Matthew Xie               if (mHeadsetProxy.getPriority(getRemoteDevice(address)) >=
247598f06da8ed2851a768358de1979838ad1bb6d187Matthew Xie                   BluetoothProfile.PRIORITY_ON) {
247698f06da8ed2851a768358de1979838ad1bb6d187Matthew Xie                   msg.what = BluetoothDeviceProfileState.CONNECT_OTHER_PROFILES;
247798f06da8ed2851a768358de1979838ad1bb6d187Matthew Xie                   msg.arg1 = BluetoothDeviceProfileState.CONNECT_HFP_OUTGOING;
247898f06da8ed2851a768358de1979838ad1bb6d187Matthew Xie                   state.sendMessageDelayed(msg,
247998f06da8ed2851a768358de1979838ad1bb6d187Matthew Xie                             BluetoothDeviceProfileState.CONNECT_OTHER_PROFILES_DELAY);
248098f06da8ed2851a768358de1979838ad1bb6d187Matthew Xie               }
248198f06da8ed2851a768358de1979838ad1bb6d187Matthew Xie           } else {
248298f06da8ed2851a768358de1979838ad1bb6d187Matthew Xie               msg.what = BluetoothDeviceProfileState.CONNECT_A2DP_INCOMING;
248398f06da8ed2851a768358de1979838ad1bb6d187Matthew Xie               state.sendMessage(msg);
248498f06da8ed2851a768358de1979838ad1bb6d187Matthew Xie           }
24859b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh           return true;
24869b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh       }
24879b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh       return false;
24889b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
24899b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
24909b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    /*package*/ void setA2dpService(BluetoothA2dpService a2dpService) {
24919b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh        mA2dpService = a2dpService;
24929b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh    }
24939b637e5985f9a86f39d70335c0390ade3716592aJaikumar Ganesh
2494a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    /*package*/ Integer getAuthorizationAgentRequestData(String address) {
2495a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        Integer data = mEventLoop.getAuthorizationAgentRequestData().remove(address);
2496a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        return data;
2497a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    }
2498a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie
249970a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh    public void sendProfileStateMessage(int profile, int cmd) {
250070a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh        Message msg = new Message();
250170a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh        msg.what = cmd;
250270a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh        if (profile == BluetoothProfileState.HFP) {
250370a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh            mHfpProfileState.sendMessage(msg);
250470a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh        } else if (profile == BluetoothProfileState.A2DP) {
250570a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh            mA2dpProfileState.sendMessage(msg);
250670a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh        }
250770a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh    }
250870a053bf1ba331d727e2fbfca8f39d96b3b324b4Jaikumar Ganesh
2509c53cab20b225ba69057441ecb06db6478ab8ff9bJaikumar Ganesh    public int getAdapterConnectionState() {
2510c53cab20b225ba69057441ecb06db6478ab8ff9bJaikumar Ganesh        return mAdapterConnectionState;
2511c53cab20b225ba69057441ecb06db6478ab8ff9bJaikumar Ganesh    }
2512c53cab20b225ba69057441ecb06db6478ab8ff9bJaikumar Ganesh
2513cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh    public int getProfileConnectionState(int profile) {
2514cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
2515cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh
2516cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh        Pair<Integer, Integer> state = mProfileConnectionState.get(profile);
2517cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh        if (state == null) return BluetoothProfile.STATE_DISCONNECTED;
2518cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh
2519cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh        return state.first;
2520cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh    }
2521cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh
2522cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh    private void updateProfileConnectionState(int profile, int newState, int oldState) {
2523cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh        // mProfileConnectionState is a hashmap -
2524cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh        // <Integer, Pair<Integer, Integer>>
2525cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh        // The key is the profile, the value is a pair. first element
2526cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh        // is the state and the second element is the number of devices
2527cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh        // in that state.
2528cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh        int numDev = 1;
2529cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh        int newHashState = newState;
2530cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh        boolean update = true;
2531cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh
2532cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh        // The following conditions are considered in this function:
2533cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh        // 1. If there is no record of profile and state - update
2534cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh        // 2. If a new device's state is current hash state - increment
2535cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh        //    number of devices in the state.
2536cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh        // 3. If a state change has happened to Connected or Connecting
2537cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh        //    (if current state is not connected), update.
2538cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh        // 4. If numDevices is 1 and that device state is being updated, update
2539cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh        // 5. If numDevices is > 1 and one of the devices is changing state,
2540cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh        //    decrement numDevices but maintain oldState if it is Connected or
2541cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh        //    Connecting
2542cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh        Pair<Integer, Integer> stateNumDev = mProfileConnectionState.get(profile);
2543cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh        if (stateNumDev != null) {
2544cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh            int currHashState = stateNumDev.first;
2545cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh            numDev = stateNumDev.second;
2546cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh
2547cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh            if (newState == currHashState) {
2548cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh                numDev ++;
2549cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh            } else if (newState == BluetoothProfile.STATE_CONNECTED ||
2550cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh                   (newState == BluetoothProfile.STATE_CONNECTING &&
2551cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh                    currHashState != BluetoothProfile.STATE_CONNECTED)) {
2552cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh                 numDev = 1;
2553cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh            } else if (numDev == 1 && oldState == currHashState) {
2554cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh                 update = true;
2555cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh            } else if (numDev > 1 && oldState == currHashState) {
2556cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh                 numDev --;
2557cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh
2558cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh                 if (currHashState == BluetoothProfile.STATE_CONNECTED ||
2559cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh                     currHashState == BluetoothProfile.STATE_CONNECTING) {
2560cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh                    newHashState = currHashState;
2561cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh                 }
2562cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh            } else {
2563cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh                 update = false;
2564cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh            }
2565cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh        }
2566cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh
2567cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh        if (update) {
2568cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh            mProfileConnectionState.put(profile, new Pair<Integer, Integer>(newHashState,
2569cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh                    numDev));
2570cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh        }
2571cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh    }
2572cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh
2573cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh    public synchronized void sendConnectionStateChange(BluetoothDevice
2574cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh            device, int profile, int state, int prevState) {
25759a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        // Since this is a binder call check if Bluetooth is on still
25767f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie        if (getBluetoothStateInternal() == BluetoothAdapter.STATE_OFF) return;
25779a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
2578cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh        if (!validateProfileConnectionState(state) ||
2579cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh                !validateProfileConnectionState(prevState)) {
2580cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh            // Previously, an invalid state was broadcast anyway,
2581cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh            // with the invalid state converted to -1 in the intent.
2582cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh            // Better to log an error and not send an intent with
2583cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh            // invalid contents or set mAdapterConnectionState to -1.
2584cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh            Log.e(TAG, "Error in sendConnectionStateChange: "
2585cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh                    + "prevState " + prevState + " state " + state);
2586cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh            return;
2587cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh        }
2588c53cab20b225ba69057441ecb06db6478ab8ff9bJaikumar Ganesh
2589cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh        updateProfileConnectionState(profile, state, prevState);
2590cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh
2591cb1d354c1e9b458a0426cd08520d938012e32b34Jaikumar Ganesh        if (updateCountersAndCheckForConnectionStateChange(state, prevState)) {
2592c53cab20b225ba69057441ecb06db6478ab8ff9bJaikumar Ganesh            mAdapterConnectionState = state;
2593c53cab20b225ba69057441ecb06db6478ab8ff9bJaikumar Ganesh
25947f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie            if (state == BluetoothProfile.STATE_DISCONNECTED) {
25957f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie                mBluetoothState.sendMessage(BluetoothAdapterStateMachine.ALL_DEVICES_DISCONNECTED);
25967f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie            }
25977f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie
2598a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh            Intent intent = new Intent(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
2599a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh            intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
26009a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            intent.putExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE,
26019a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                    convertToAdapterState(state));
26029a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_CONNECTION_STATE,
26039a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                    convertToAdapterState(prevState));
260460b4d2a2bd232a7116fd037501cac704f328c0a1Jaikumar Ganesh            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
2605a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh            mContext.sendBroadcast(intent, BLUETOOTH_PERM);
26069a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            Log.d(TAG, "CONNECTION_STATE_CHANGE: " + device + ": "
26079a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                    + prevState + " -> " + state);
2608a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh        }
2609a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh    }
2610a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh
26119a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    private boolean validateProfileConnectionState(int state) {
26129a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        return (state == BluetoothProfile.STATE_DISCONNECTED ||
26139a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                state == BluetoothProfile.STATE_CONNECTING ||
26149a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                state == BluetoothProfile.STATE_CONNECTED ||
26159a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                state == BluetoothProfile.STATE_DISCONNECTING);
26169a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    }
26179a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
26189a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    private int convertToAdapterState(int state) {
2619a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh        switch (state) {
26209a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            case BluetoothProfile.STATE_DISCONNECTED:
26219a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                return BluetoothAdapter.STATE_DISCONNECTED;
26229a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            case BluetoothProfile.STATE_DISCONNECTING:
26239a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                return BluetoothAdapter.STATE_DISCONNECTING;
26249a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            case BluetoothProfile.STATE_CONNECTED:
26259a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                return BluetoothAdapter.STATE_CONNECTED;
2626a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh            case BluetoothProfile.STATE_CONNECTING:
2627a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh                return BluetoothAdapter.STATE_CONNECTING;
26289a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        }
26299a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        Log.e(TAG, "Error in convertToAdapterState");
26309a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        return -1;
26319a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    }
26329a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
26339a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    private boolean updateCountersAndCheckForConnectionStateChange(int state, int prevState) {
26349a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby        switch (prevState) {
26359a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            case BluetoothProfile.STATE_CONNECTING:
26369a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                mProfilesConnecting--;
26379a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                break;
26389a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
2639a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh            case BluetoothProfile.STATE_CONNECTED:
26409a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                mProfilesConnected--;
26419a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                break;
26429a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby
2643a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh            case BluetoothProfile.STATE_DISCONNECTING:
26449a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                mProfilesDisconnecting--;
26459a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                break;
2646a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh        }
2647a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh
2648a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh        switch (state) {
2649a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh            case BluetoothProfile.STATE_CONNECTING:
2650a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh                mProfilesConnecting++;
26519a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                return (mProfilesConnected == 0 && mProfilesConnecting == 1);
2652a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh
2653a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh            case BluetoothProfile.STATE_CONNECTED:
2654a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh                mProfilesConnected++;
26559a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                return (mProfilesConnected == 1);
2656a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh
2657a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh            case BluetoothProfile.STATE_DISCONNECTING:
2658a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh                mProfilesDisconnecting++;
26599a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                return (mProfilesConnected == 0 && mProfilesDisconnecting == 1);
2660a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh
2661a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh            case BluetoothProfile.STATE_DISCONNECTED:
26629a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                return (mProfilesConnected == 0 && mProfilesConnecting == 0);
2663a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh
26649a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby            default:
26659a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby                return true;
2666a46f2fb152355fe591f9dddeb41f01fef5ccad1dJaikumar Ganesh        }
26679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2668d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
2669a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    private void createIncomingConnectionStateFile() {
2670a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        File f = new File(INCOMING_CONNECTION_FILE);
2671a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        if (!f.exists()) {
2672a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            try {
2673a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                f.createNewFile();
2674a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            } catch (IOException e) {
2675a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                Log.e(TAG, "IOException: cannot create file");
2676a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            }
2677a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        }
2678a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    }
2679a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie
2680a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    /** @hide */
2681a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    public Pair<Integer, String> getIncomingState(String address) {
2682a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        if (mIncomingConnections.isEmpty()) {
2683a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            createIncomingConnectionStateFile();
2684a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            readIncomingConnectionState();
2685a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        }
2686a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        return mIncomingConnections.get(address);
2687a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    }
2688a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie
2689a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    private void readIncomingConnectionState() {
2690a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        synchronized(mIncomingConnections) {
2691a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            FileInputStream fstream = null;
2692a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            try {
2693a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie              fstream = new FileInputStream(INCOMING_CONNECTION_FILE);
2694a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie              DataInputStream in = new DataInputStream(fstream);
2695a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie              BufferedReader file = new BufferedReader(new InputStreamReader(in));
2696a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie              String line;
2697a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie              while((line = file.readLine()) != null) {
2698a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                  line = line.trim();
2699a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                  if (line.length() == 0) continue;
2700a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                  String[] value = line.split(",");
2701a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                  if (value != null && value.length == 3) {
2702a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                      Integer val1 = Integer.parseInt(value[1]);
2703a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                      Pair<Integer, String> val = new Pair(val1, value[2]);
2704a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                      mIncomingConnections.put(value[0], val);
2705a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                  }
2706a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie              }
2707a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            } catch (FileNotFoundException e) {
2708a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                log("FileNotFoundException: readIncomingConnectionState" + e.toString());
2709a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            } catch (IOException e) {
2710a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                log("IOException: readIncomingConnectionState" + e.toString());
2711a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            } finally {
2712a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                if (fstream != null) {
2713a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                    try {
2714a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                        fstream.close();
2715a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                    } catch (IOException e) {
2716a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                        // Ignore
2717a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                    }
2718a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                }
2719a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            }
2720a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        }
2721a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    }
2722a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie
2723a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    private void truncateIncomingConnectionFile() {
2724a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        RandomAccessFile r = null;
2725a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        try {
2726a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            r = new RandomAccessFile(INCOMING_CONNECTION_FILE, "rw");
2727a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            r.setLength(0);
2728a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        } catch (FileNotFoundException e) {
2729a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            log("FileNotFoundException: truncateIncomingConnectionState" + e.toString());
2730a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        } catch (IOException e) {
2731a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            log("IOException: truncateIncomingConnectionState" + e.toString());
2732a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        } finally {
2733a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            if (r != null) {
2734a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                try {
2735a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                    r.close();
2736a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                } catch (IOException e) {
2737a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                    // ignore
2738a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                 }
2739a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            }
2740a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        }
2741a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    }
2742a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie
2743a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    /** @hide */
2744a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    public void writeIncomingConnectionState(String address, Pair<Integer, String> data) {
2745a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        synchronized(mIncomingConnections) {
2746a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            mIncomingConnections.put(address, data);
2747a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie
2748a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            truncateIncomingConnectionFile();
2749a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            BufferedWriter out = null;
2750a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            StringBuilder value = new StringBuilder();
2751a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            try {
2752a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                out = new BufferedWriter(new FileWriter(INCOMING_CONNECTION_FILE, true));
2753a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                for (String devAddress: mIncomingConnections.keySet()) {
2754a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                  Pair<Integer, String> val = mIncomingConnections.get(devAddress);
2755a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                  value.append(devAddress);
2756a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                  value.append(",");
2757a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                  value.append(val.first.toString());
2758a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                  value.append(",");
2759a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                  value.append(val.second);
2760a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                  value.append("\n");
2761a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                }
2762a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                out.write(value.toString());
2763a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            } catch (FileNotFoundException e) {
2764a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                log("FileNotFoundException: writeIncomingConnectionState" + e.toString());
2765a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            } catch (IOException e) {
2766a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                log("IOException: writeIncomingConnectionState" + e.toString());
2767a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            } finally {
2768a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                if (out != null) {
2769a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                    try {
2770a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                        out.close();
2771a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                    } catch (IOException e) {
2772a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                        // Ignore
2773a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                    }
2774a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie                }
2775a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie            }
2776a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        }
2777a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    }
2778a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie
2779a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    private static void log(String msg) {
2780a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie        Log.d(TAG, msg);
2781a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    }
2782a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie
2783d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native static void classInitNative();
2784d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native void initializeNativeDataNative();
2785d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setupNativeDataNative();
2786d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean tearDownNativeDataNative();
2787d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native void cleanupNativeDataNative();
27889a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    /*package*/ native String getAdapterPathNative();
2789d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
2790d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native int isEnabledNative();
27917f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    /*package*/ native int enableNative();
27927f9ecca8f2dc288f785b37d2478e89b80fc3cefcMatthew Xie    /*package*/ native int disableNative();
2793d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
27949a62c9cd6585656f4e29ba971b1f88a510d674bdJake Hamby    /*package*/ native Object[] getAdapterPropertiesNative();
2795d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native Object[] getDevicePropertiesNative(String objectPath);
2796d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setAdapterPropertyStringNative(String key, String value);
2797d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setAdapterPropertyIntegerNative(String key, int value);
2798d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setAdapterPropertyBooleanNative(String key, int value);
2799d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
2800d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean startDiscoveryNative();
2801d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean stopDiscoveryNative();
2802d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
2803d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean createPairedDeviceNative(String address, int timeout_ms);
2804cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    private native boolean createPairedDeviceOutOfBandNative(String address, int timeout_ms);
2805cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    private native byte[] readAdapterOutOfBandDataNative();
2806cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
2807d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean cancelDeviceCreationNative(String address);
2808d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean removeDeviceNative(String objectPath);
2809d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native int getDeviceServiceChannelNative(String objectPath, String uuid,
2810d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh            int attributeId);
2811d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh
2812b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    private native boolean cancelPairingUserInputNative(String address, int nativeData);
2813d5ac1ae36b4e096eb97984334f86d0c68abea2f7Jaikumar Ganesh    private native boolean setPinNative(String address, String pin, int nativeData);
2814b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    private native boolean setPasskeyNative(String address, int passkey, int nativeData);
2815b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh    private native boolean setPairingConfirmationNative(String address, boolean confirm,
2816b0eca41de0bb6747d8648b134912782e45e4cbefJaikumar Ganesh            int nativeData);
2817cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh    private native boolean setRemoteOutOfBandDataNative(String address, byte[] hash,
2818cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh                                                        byte[] randomizer, int nativeData);
2819cc5494c9996f809e36539b24e8b6b67683383d29Jaikumar Ganesh
282024bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private native boolean setDevicePropertyBooleanNative(String objectPath, String key,
282124bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            int value);
2822269e81a563cfe080d7f241d0d46411d3c946c111Matthew Xie    private native boolean setDevicePropertyStringNative(String objectPath, String key,
2823269e81a563cfe080d7f241d0d46411d3c946c111Matthew Xie            String value);
28241caa6d111eff6814760ec156b14adc29aa3aae6cJaikumar Ganesh    private native boolean createDeviceNative(String address);
282516fb88a673c41b93c5d57ccb28c2697e7d87701aNick Pelly    /*package*/ native boolean discoverServicesNative(String objectPath, String pattern);
282610eac971b3a6e5f34a420dd68ebfa796553ad2b9Jaikumar Ganesh
282724bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private native int addRfcommServiceRecordNative(String name, long uuidMsb, long uuidLsb,
282824bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly            short channel);
282924bb9b8af4ff691538fe9e517e8156016b0da6cdNick Pelly    private native boolean removeServiceRecordNative(int handle);
2830b7e029d03c115ed65cdea9b2bba307e882c308e2Jaikumar Ganesh    private native boolean setLinkTimeoutNative(String path, int num_slots);
2831a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie
283230b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    native boolean connectInputDeviceNative(String path);
283330b8cbe059b9addff643242e8a1fc86ca72ba54eJaikumar Ganesh    native boolean disconnectInputDeviceNative(String path);
28346fdd0c6274c81b337ad35b70480f881daf7354c3Danica Chang
2835a8571f15c39da2b7c6e672fef26106f5ac60dea0Jaikumar Ganesh    native boolean setBluetoothTetheringNative(boolean value, String nap, String bridge);
2836a8571f15c39da2b7c6e672fef26106f5ac60dea0Jaikumar Ganesh    native boolean connectPanDeviceNative(String path, String dstRole);
2837a8571f15c39da2b7c6e672fef26106f5ac60dea0Jaikumar Ganesh    native boolean disconnectPanDeviceNative(String path);
2838a8571f15c39da2b7c6e672fef26106f5ac60dea0Jaikumar Ganesh    native boolean disconnectPanServerDeviceNative(String path,
2839a44a1e77ef435942b2ff60e9e60d3a64b43d775bJaikumar Ganesh            String address, String iface);
284084690c88f37f395094147d27ace8319a2803a522Jaikumar Ganesh
284184690c88f37f395094147d27ace8319a2803a522Jaikumar Ganesh    private native int[] addReservedServiceRecordsNative(int[] uuuids);
284284690c88f37f395094147d27ace8319a2803a522Jaikumar Ganesh    private native boolean removeReservedServiceRecordsNative(int[] handles);
28432ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh
28442ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    // Health API
28452ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    native String registerHealthApplicationNative(int dataType, String role, String name,
28462ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh            String channelType);
28472ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    native String registerHealthApplicationNative(int dataType, String role, String name);
28482ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    native boolean unregisterHealthApplicationNative(String path);
2849b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh    native boolean createChannelNative(String devicePath, String appPath, String channelType,
2850b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh                                       int code);
2851b5d2d4526cd2c0117b7a33b1297ac683c37ac5c7Jaikumar Ganesh    native boolean destroyChannelNative(String devicePath, String channelpath, int code);
28522ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    native String getMainChannelNative(String path);
28532ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    native String getChannelApplicationNative(String channelPath);
28542ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    native ParcelFileDescriptor getChannelFdNative(String channelPath);
28552ea1e85dcb57d17f5782dbafa1d25eb51c630e4bJaikumar Ganesh    native boolean releaseChannelFdNative(String channelPath);
2856a0c680393f2dd03a937c598b2cb9abf98a58152cMatthew Xie    native boolean setAuthorizationNative(String address, boolean value, int data);
28579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
2858