blob: afc96768c38d85043a6e7a35e5af53347bfdc171 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.server;
18
19import android.bluetooth.BluetoothA2dp;
Nick Pellybd022f42009-08-14 18:33:38 -070020import android.bluetooth.BluetoothAdapter;
Jaikumar Ganesh32d85712009-09-10 22:00:05 -070021import android.bluetooth.BluetoothClass;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022import android.bluetooth.BluetoothDevice;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070023import android.bluetooth.BluetoothInputDevice;
Danica Chang6fdd0c62010-08-11 14:54:43 -070024import android.bluetooth.BluetoothPan;
Jaikumar Ganesh96a79832010-09-27 17:02:01 -070025import android.bluetooth.BluetoothProfile;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -070026import android.bluetooth.BluetoothUuid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080027import android.content.Context;
28import android.content.Intent;
29import android.os.Handler;
30import android.os.Message;
Jaikumar Ganesh577dd1f2009-12-17 14:59:10 -080031import android.os.ParcelUuid;
Jaikumar Ganesh5a1e4cf2010-10-18 17:05:09 -070032import android.os.PowerManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033import android.util.Log;
34
35import java.util.HashMap;
Jaikumar Ganesh5a1e4cf2010-10-18 17:05:09 -070036import java.util.List;
Bheemsen Kulkarniabf99432010-03-17 14:56:00 +053037
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038
39/**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040 * @hide
41 */
42class BluetoothEventLoop {
43 private static final String TAG = "BluetoothEventLoop";
44 private static final boolean DBG = false;
45
46 private int mNativeData;
47 private Thread mThread;
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -070048 private boolean mStarted;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049 private boolean mInterrupted;
Nick Pellybd022f42009-08-14 18:33:38 -070050
The Android Open Source Project10592532009-03-18 17:39:46 -070051 private final HashMap<String, Integer> mPasskeyAgentRequestData;
Matthew Xiea0c68032011-06-25 21:47:07 -070052 private final HashMap<String, Integer> mAuthorizationAgentRequestData;
Nick Pellybd022f42009-08-14 18:33:38 -070053 private final BluetoothService mBluetoothService;
54 private final BluetoothAdapter mAdapter;
Matthew Xie7f9ecca2011-07-15 13:03:58 -070055 private final BluetoothAdapterStateMachine mBluetoothState;
Jaikumar Ganesh96a79832010-09-27 17:02:01 -070056 private BluetoothA2dp mA2dp;
The Android Open Source Project10592532009-03-18 17:39:46 -070057 private final Context mContext;
Bheemsen Kulkarniabf99432010-03-17 14:56:00 +053058 // The WakeLock is used for bringing up the LCD during a pairing request
59 // from remote device when Android is in Suspend state.
60 private PowerManager.WakeLock mWakeLock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061
Jaikumar Ganesha224f702010-09-10 15:09:54 -070062 private static final int EVENT_RESTART_BLUETOOTH = 1;
63 private static final int EVENT_PAIRING_CONSENT_DELAYED_ACCEPT = 2;
64 private static final int EVENT_AGENT_CANCEL = 3;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080065
Nick Pelly16fb88a2009-10-07 07:44:03 +020066 private static final int CREATE_DEVICE_ALREADY_EXISTS = 1;
67 private static final int CREATE_DEVICE_SUCCESS = 0;
68 private static final int CREATE_DEVICE_FAILED = -1;
69
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070 private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
71 private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
72
73 private final Handler mHandler = new Handler() {
74 @Override
75 public void handleMessage(Message msg) {
Jaikumar Ganesh32d85712009-09-10 22:00:05 -070076 String address = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080077 switch (msg.what) {
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -070078 case EVENT_RESTART_BLUETOOTH:
Nick Pelly37b5a102009-03-24 20:46:18 -070079 mBluetoothService.restart();
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -070080 break;
Jaikumar Ganesh32d85712009-09-10 22:00:05 -070081 case EVENT_PAIRING_CONSENT_DELAYED_ACCEPT:
82 address = (String)msg.obj;
83 if (address != null) {
84 mBluetoothService.setPairingConfirmation(address, true);
85 }
86 break;
Jaikumar Ganeshe5d93b72009-10-08 02:27:52 -070087 case EVENT_AGENT_CANCEL:
88 // Set the Bond State to BOND_NONE.
89 // We always have only 1 device in BONDING state.
Jaikumar Ganesha224f702010-09-10 15:09:54 -070090 String[] devices = mBluetoothService.listInState(BluetoothDevice.BOND_BONDING);
Jaikumar Ganeshe5d93b72009-10-08 02:27:52 -070091 if (devices.length == 0) {
92 break;
93 } else if (devices.length > 1) {
94 Log.e(TAG, " There is more than one device in the Bonding State");
95 break;
96 }
97 address = devices[0];
Jaikumar Ganesha224f702010-09-10 15:09:54 -070098 mBluetoothService.setBondState(address,
Jaikumar Ganeshe5d93b72009-10-08 02:27:52 -070099 BluetoothDevice.BOND_NONE,
100 BluetoothDevice.UNBOND_REASON_REMOTE_AUTH_CANCELED);
101 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102 }
103 }
104 };
105
106 static { classInitNative(); }
107 private static native void classInitNative();
108
Jaikumar Ganesha224f702010-09-10 15:09:54 -0700109 /* package */ BluetoothEventLoop(Context context, BluetoothAdapter adapter,
Matthew Xie7f9ecca2011-07-15 13:03:58 -0700110 BluetoothService bluetoothService,
111 BluetoothAdapterStateMachine bluetoothState) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800112 mBluetoothService = bluetoothService;
113 mContext = context;
Matthew Xie7f9ecca2011-07-15 13:03:58 -0700114 mBluetoothState = bluetoothState;
Jake Hamby9a62c9c2010-12-09 14:47:57 -0800115 mPasskeyAgentRequestData = new HashMap<String, Integer>();
Matthew Xiea0c68032011-06-25 21:47:07 -0700116 mAuthorizationAgentRequestData = new HashMap<String, Integer>();
Nick Pellybd022f42009-08-14 18:33:38 -0700117 mAdapter = adapter;
Bheemsen Kulkarniabf99432010-03-17 14:56:00 +0530118 //WakeLock instantiation in BluetoothEventLoop class
119 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
120 mWakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP
121 | PowerManager.ON_AFTER_RELEASE, TAG);
122 mWakeLock.setReferenceCounted(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800123 initializeNativeDataNative();
Jaikumar Ganesh7d0548d2010-10-18 15:29:09 -0700124 }
Jaikumar Ganesh96a79832010-09-27 17:02:01 -0700125
Jaikumar Ganesh7d0548d2010-10-18 15:29:09 -0700126 /*package*/ void getProfileProxy() {
Jaikumar Ganesh96a79832010-09-27 17:02:01 -0700127 mAdapter.getProfileProxy(mContext, mProfileServiceListener, BluetoothProfile.A2DP);
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800128 mAdapter.getProfileProxy(mContext, mProfileServiceListener, BluetoothProfile.INPUT_DEVICE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800129 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800130
Jaikumar Ganesh96a79832010-09-27 17:02:01 -0700131 private BluetoothProfile.ServiceListener mProfileServiceListener =
132 new BluetoothProfile.ServiceListener() {
133 public void onServiceConnected(int profile, BluetoothProfile proxy) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800134 if (profile == BluetoothProfile.A2DP) {
135 mA2dp = (BluetoothA2dp) proxy;
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800136 }
Jaikumar Ganesh96a79832010-09-27 17:02:01 -0700137 }
138 public void onServiceDisconnected(int profile) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800139 if (profile == BluetoothProfile.A2DP) {
140 mA2dp = null;
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800141 }
Jaikumar Ganesh96a79832010-09-27 17:02:01 -0700142 }
143 };
144
145
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800146 protected void finalize() throws Throwable {
147 try {
148 cleanupNativeDataNative();
149 } finally {
150 super.finalize();
151 }
152 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800153
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700154 /* package */ HashMap<String, Integer> getPasskeyAgentRequestData() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800155 return mPasskeyAgentRequestData;
156 }
157
Matthew Xiea0c68032011-06-25 21:47:07 -0700158 /* package */ HashMap<String, Integer> getAuthorizationAgentRequestData() {
159 return mAuthorizationAgentRequestData;
160 }
161
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700162 /* package */ void start() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800163
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700164 if (!isEventLoopRunningNative()) {
165 if (DBG) log("Starting Event Loop thread");
166 startEventLoopNative();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800167 }
168 }
169
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700170 public void stop() {
171 if (isEventLoopRunningNative()) {
172 if (DBG) log("Stopping Event Loop thread");
173 stopEventLoopNative();
174 }
175 }
176
177 public boolean isEventLoopRunning() {
178 return isEventLoopRunningNative();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800179 }
180
Jaikumar Ganesh9488cbd2009-08-03 17:17:37 -0700181 private void addDevice(String address, String[] properties) {
Jake Hamby9a62c9c2010-12-09 14:47:57 -0800182 BluetoothDeviceProperties deviceProperties =
183 mBluetoothService.getDeviceProperties();
184 deviceProperties.addProperties(address, properties);
185 String rssi = deviceProperties.getProperty(address, "RSSI");
186 String classValue = deviceProperties.getProperty(address, "Class");
187 String name = deviceProperties.getProperty(address, "Name");
Jaikumar Ganesh9488cbd2009-08-03 17:17:37 -0700188 short rssiValue;
189 // For incoming connections, we don't get the RSSI value. Use a default of MIN_VALUE.
190 // If we accept the pairing, we will automatically show it at the top of the list.
191 if (rssi != null) {
192 rssiValue = (short)Integer.valueOf(rssi).intValue();
193 } else {
194 rssiValue = Short.MIN_VALUE;
195 }
196 if (classValue != null) {
Nick Pelly005b2282009-09-10 10:21:56 -0700197 Intent intent = new Intent(BluetoothDevice.ACTION_FOUND);
198 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
199 intent.putExtra(BluetoothDevice.EXTRA_CLASS,
200 new BluetoothClass(Integer.valueOf(classValue)));
201 intent.putExtra(BluetoothDevice.EXTRA_RSSI, rssiValue);
202 intent.putExtra(BluetoothDevice.EXTRA_NAME, name);
Jaikumar Ganesh9488cbd2009-08-03 17:17:37 -0700203
204 mContext.sendBroadcast(intent, BLUETOOTH_PERM);
205 } else {
206 log ("ClassValue: " + classValue + " for remote device: " + address + " is null");
207 }
208 }
209
Jake Hamby9a62c9c2010-12-09 14:47:57 -0800210 /**
211 * Called by native code on a DeviceFound signal from org.bluez.Adapter.
212 *
213 * @param address the MAC address of the new device
214 * @param properties an array of property keys and value strings
215 *
216 * @see BluetoothDeviceProperties#addProperties(String, String[])
217 */
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700218 private void onDeviceFound(String address, String[] properties) {
219 if (properties == null) {
220 Log.e(TAG, "ERROR: Remote device properties are null");
221 return;
222 }
Jaikumar Ganesh9488cbd2009-08-03 17:17:37 -0700223 addDevice(address, properties);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800224 }
225
Jake Hamby9a62c9c2010-12-09 14:47:57 -0800226 /**
227 * Called by native code on a DeviceDisappeared signal from
228 * org.bluez.Adapter.
229 *
230 * @param address the MAC address of the disappeared device
231 */
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700232 private void onDeviceDisappeared(String address) {
Nick Pelly005b2282009-09-10 10:21:56 -0700233 Intent intent = new Intent(BluetoothDevice.ACTION_DISAPPEARED);
234 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800235 mContext.sendBroadcast(intent, BLUETOOTH_PERM);
236 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800237
Jake Hamby9a62c9c2010-12-09 14:47:57 -0800238 /**
239 * Called by native code on a DisconnectRequested signal from
240 * org.bluez.Device.
241 *
242 * @param deviceObjectPath the object path for the disconnecting device
243 */
Jaikumar Ganesh5e59ca82009-09-11 12:16:19 -0700244 private void onDeviceDisconnectRequested(String deviceObjectPath) {
245 String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath);
246 if (address == null) {
247 Log.e(TAG, "onDeviceDisconnectRequested: Address of the remote device in null");
248 return;
249 }
250 Intent intent = new Intent(BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED);
251 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
252 mContext.sendBroadcast(intent, BLUETOOTH_PERM);
253 }
254
Jake Hamby9a62c9c2010-12-09 14:47:57 -0800255 /**
256 * Called by native code for the async response to a CreatePairedDevice
257 * method call to org.bluez.Adapter.
258 *
259 * @param address the MAC address of the device to pair
260 * @param result success or error result for the pairing operation
261 */
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700262 private void onCreatePairedDeviceResult(String address, int result) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800263 address = address.toUpperCase();
Jaikumar Ganesha224f702010-09-10 15:09:54 -0700264 mBluetoothService.onCreatePairedDeviceResult(address, result);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800265 }
266
Jake Hamby9a62c9c2010-12-09 14:47:57 -0800267 /**
268 * Called by native code on a DeviceCreated signal from org.bluez.Adapter.
269 *
270 * @param deviceObjectPath the object path for the created device
271 */
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700272 private void onDeviceCreated(String deviceObjectPath) {
Jaikumar Ganesh9488cbd2009-08-03 17:17:37 -0700273 String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath);
274 if (!mBluetoothService.isRemoteDeviceInCache(address)) {
275 // Incoming connection, we haven't seen this device, add to cache.
276 String[] properties = mBluetoothService.getRemoteDeviceProperties(address);
277 if (properties != null) {
278 addDevice(address, properties);
279 }
280 }
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700281 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800282 }
283
Jake Hamby9a62c9c2010-12-09 14:47:57 -0800284 /**
285 * Called by native code on a DeviceRemoved signal from org.bluez.Adapter.
286 *
287 * @param deviceObjectPath the object path for the removed device
288 */
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700289 private void onDeviceRemoved(String deviceObjectPath) {
290 String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath);
Jaikumar Ganesh081a9b69a2010-03-02 17:19:20 -0800291 if (address != null) {
Jaikumar Ganesha224f702010-09-10 15:09:54 -0700292 mBluetoothService.setBondState(address.toUpperCase(), BluetoothDevice.BOND_NONE,
293 BluetoothDevice.UNBOND_REASON_REMOVED);
Jaikumar Ganesh081a9b69a2010-03-02 17:19:20 -0800294 mBluetoothService.setRemoteDeviceProperty(address, "UUIDs", null);
295 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800296 }
297
Jake Hamby9a62c9c2010-12-09 14:47:57 -0800298 /**
299 * Called by native code on a PropertyChanged signal from
Matthew Xie7f9ecca2011-07-15 13:03:58 -0700300 * org.bluez.Adapter. This method is also called from
301 * {@link BluetoothAdapterStateMachine} to set the "Pairable"
Jake Hamby9a62c9c2010-12-09 14:47:57 -0800302 * property when Bluetooth is enabled.
303 *
304 * @param propValues a string array containing the key and one or more
305 * values.
306 */
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700307 /*package*/ void onPropertyChanged(String[] propValues) {
Jake Hamby9a62c9c2010-12-09 14:47:57 -0800308 BluetoothAdapterProperties adapterProperties =
309 mBluetoothService.getAdapterProperties();
310
311 if (adapterProperties.isEmpty()) {
Jaikumar Ganesh9519ce72009-09-08 21:37:32 -0700312 // We have got a property change before
313 // we filled up our cache.
Jake Hamby9a62c9c2010-12-09 14:47:57 -0800314 adapterProperties.getAllProperties();
Jaikumar Ganesh9519ce72009-09-08 21:37:32 -0700315 }
Jaikumar Ganeshb1ef2442010-10-26 00:14:04 -0700316 log("Property Changed: " + propValues[0] + " : " + propValues[1]);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700317 String name = propValues[0];
318 if (name.equals("Name")) {
Jake Hamby9a62c9c2010-12-09 14:47:57 -0800319 adapterProperties.setProperty(name, propValues[1]);
Jaikumar Ganesh6a9d93c2009-09-20 11:48:16 -0700320 Intent intent = new Intent(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
321 intent.putExtra(BluetoothAdapter.EXTRA_LOCAL_NAME, propValues[1]);
Jaikumar Ganesh6a3c4732010-12-15 13:12:57 -0800322 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700323 mContext.sendBroadcast(intent, BLUETOOTH_PERM);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700324 } else if (name.equals("Pairable") || name.equals("Discoverable")) {
325 String pairable = name.equals("Pairable") ? propValues[1] :
Jake Hamby9a62c9c2010-12-09 14:47:57 -0800326 adapterProperties.getProperty("Pairable");
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700327 String discoverable = name.equals("Discoverable") ? propValues[1] :
Jake Hamby9a62c9c2010-12-09 14:47:57 -0800328 adapterProperties.getProperty("Discoverable");
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700329
330 // This shouldn't happen, unless Adapter Properties are null.
331 if (pairable == null || discoverable == null)
332 return;
333
Jake Hamby9a62c9c2010-12-09 14:47:57 -0800334 adapterProperties.setProperty(name, propValues[1]);
Matthew Xie7f9ecca2011-07-15 13:03:58 -0700335
336 if (name.equals("Pairable")) {
337 if (pairable.equals("true")) {
Jaikumar Ganeshef2cb7c2011-07-21 18:13:38 -0700338 mBluetoothState.sendMessage(BluetoothAdapterStateMachine.BECAME_PAIRABLE);
Matthew Xie7f9ecca2011-07-15 13:03:58 -0700339 } else {
Jaikumar Ganeshef2cb7c2011-07-21 18:13:38 -0700340 mBluetoothState.sendMessage(BluetoothAdapterStateMachine.BECAME_NON_PAIRABLE);
Matthew Xie7f9ecca2011-07-15 13:03:58 -0700341 }
342 }
343
Nick Pellybd022f42009-08-14 18:33:38 -0700344 int mode = BluetoothService.bluezStringToScanMode(
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700345 pairable.equals("true"),
346 discoverable.equals("true"));
347 if (mode >= 0) {
Nick Pellyde893f52009-09-08 13:15:33 -0700348 Intent intent = new Intent(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
349 intent.putExtra(BluetoothAdapter.EXTRA_SCAN_MODE, mode);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700350 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
351 mContext.sendBroadcast(intent, BLUETOOTH_PERM);
352 }
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700353 } else if (name.equals("Discovering")) {
354 Intent intent;
Jake Hamby9a62c9c2010-12-09 14:47:57 -0800355 adapterProperties.setProperty(name, propValues[1]);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700356 if (propValues[1].equals("true")) {
357 mBluetoothService.setIsDiscovering(true);
Nick Pelly005b2282009-09-10 10:21:56 -0700358 intent = new Intent(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700359 } else {
Jake Hamby39657b82010-11-19 16:45:58 -0800360 // Stop the discovery.
361 mBluetoothService.cancelDiscovery();
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700362 mBluetoothService.setIsDiscovering(false);
Nick Pelly005b2282009-09-10 10:21:56 -0700363 intent = new Intent(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700364 }
365 mContext.sendBroadcast(intent, BLUETOOTH_PERM);
Jaikumar Ganesh84690c82010-12-10 12:48:58 -0800366 } else if (name.equals("Devices") || name.equals("UUIDs")) {
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700367 String value = null;
368 int len = Integer.valueOf(propValues[1]);
369 if (len > 0) {
Jaikumar Ganeshefa33672009-08-28 13:48:55 -0700370 StringBuilder str = new StringBuilder();
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700371 for (int i = 2; i < propValues.length; i++) {
Jaikumar Ganeshefa33672009-08-28 13:48:55 -0700372 str.append(propValues[i]);
373 str.append(",");
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700374 }
Jaikumar Ganeshefa33672009-08-28 13:48:55 -0700375 value = str.toString();
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700376 }
Jake Hamby9a62c9c2010-12-09 14:47:57 -0800377 adapterProperties.setProperty(name, value);
Jaikumar Ganesh50b40ce2011-02-02 14:44:49 -0800378 if (name.equals("UUIDs")) {
379 mBluetoothService.updateBluetoothState(value);
380 }
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700381 } else if (name.equals("Powered")) {
382 // bluetoothd has restarted, re-read all our properties.
383 // Note: bluez only sends this property change when it restarts.
384 if (propValues[1].equals("true"))
385 onRestartRequired();
Jaikumar Ganeshff7db402010-10-25 16:25:52 -0700386 } else if (name.equals("DiscoverableTimeout")) {
Jake Hamby9a62c9c2010-12-09 14:47:57 -0800387 adapterProperties.setProperty(name, propValues[1]);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700388 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800389 }
390
Jake Hamby9a62c9c2010-12-09 14:47:57 -0800391 /**
392 * Called by native code on a PropertyChanged signal from
393 * org.bluez.Device.
394 *
395 * @param deviceObjectPath the object path for the changed device
396 * @param propValues a string array containing the key and one or more
397 * values.
398 */
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700399 private void onDevicePropertyChanged(String deviceObjectPath, String[] propValues) {
400 String name = propValues[0];
401 String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath);
402 if (address == null) {
403 Log.e(TAG, "onDevicePropertyChanged: Address of the remote device in null");
404 return;
405 }
Jaikumar Ganeshb1ef2442010-10-26 00:14:04 -0700406 log("Device property changed: " + address + " property: "
407 + name + " value: " + propValues[1]);
408
Nick Pellybd022f42009-08-14 18:33:38 -0700409 BluetoothDevice device = mAdapter.getRemoteDevice(address);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700410 if (name.equals("Name")) {
Jaikumar Ganesh2dfe1012010-09-29 10:31:02 -0700411 mBluetoothService.setRemoteDeviceProperty(address, name, propValues[1]);
Nick Pelly005b2282009-09-10 10:21:56 -0700412 Intent intent = new Intent(BluetoothDevice.ACTION_NAME_CHANGED);
413 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
414 intent.putExtra(BluetoothDevice.EXTRA_NAME, propValues[1]);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700415 mContext.sendBroadcast(intent, BLUETOOTH_PERM);
Matthew Xie269e81a2011-07-26 18:36:49 -0700416 } else if (name.equals("Alias")) {
417 mBluetoothService.setRemoteDeviceProperty(address, name, propValues[1]);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700418 } else if (name.equals("Class")) {
Jaikumar Ganesh2dfe1012010-09-29 10:31:02 -0700419 mBluetoothService.setRemoteDeviceProperty(address, name, propValues[1]);
Nick Pelly005b2282009-09-10 10:21:56 -0700420 Intent intent = new Intent(BluetoothDevice.ACTION_CLASS_CHANGED);
421 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
422 intent.putExtra(BluetoothDevice.EXTRA_CLASS,
423 new BluetoothClass(Integer.valueOf(propValues[1])));
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700424 mContext.sendBroadcast(intent, BLUETOOTH_PERM);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700425 } else if (name.equals("Connected")) {
Jaikumar Ganesh2dfe1012010-09-29 10:31:02 -0700426 mBluetoothService.setRemoteDeviceProperty(address, name, propValues[1]);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700427 Intent intent = null;
428 if (propValues[1].equals("true")) {
Nick Pelly005b2282009-09-10 10:21:56 -0700429 intent = new Intent(BluetoothDevice.ACTION_ACL_CONNECTED);
Jaikumar Ganeshb7e029d2010-03-09 15:31:24 -0800430 // Set the link timeout to 8000 slots (5 sec timeout)
431 // for bluetooth docks.
432 if (mBluetoothService.isBluetoothDock(address)) {
433 mBluetoothService.setLinkTimeout(address, 8000);
434 }
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700435 } else {
Nick Pelly005b2282009-09-10 10:21:56 -0700436 intent = new Intent(BluetoothDevice.ACTION_ACL_DISCONNECTED);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700437 }
Nick Pelly005b2282009-09-10 10:21:56 -0700438 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700439 mContext.sendBroadcast(intent, BLUETOOTH_PERM);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700440 } else if (name.equals("UUIDs")) {
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700441 String uuid = null;
442 int len = Integer.valueOf(propValues[1]);
443 if (len > 0) {
Jaikumar Ganeshefa33672009-08-28 13:48:55 -0700444 StringBuilder str = new StringBuilder();
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700445 for (int i = 2; i < propValues.length; i++) {
Jaikumar Ganeshefa33672009-08-28 13:48:55 -0700446 str.append(propValues[i]);
447 str.append(",");
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700448 }
Jaikumar Ganeshefa33672009-08-28 13:48:55 -0700449 uuid = str.toString();
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700450 }
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700451 mBluetoothService.setRemoteDeviceProperty(address, name, uuid);
Jaikumar Ganesh10eac972009-09-21 12:48:51 -0700452
453 // UUIDs have changed, query remote service channel and update cache.
454 mBluetoothService.updateDeviceServiceChannelCache(address);
455
Jaikumar Ganesh1caa6d12009-09-18 11:32:54 -0700456 mBluetoothService.sendUuidIntent(address);
Jaikumar Ganesh9488cbd2009-08-03 17:17:37 -0700457 } else if (name.equals("Paired")) {
458 if (propValues[1].equals("true")) {
Henrik Backlund42264152010-08-30 11:59:42 +0200459 // If locally initiated pairing, we will
460 // not go to BOND_BONDED state until we have received a
461 // successful return value in onCreatePairedDeviceResult
Jaikumar Ganesha224f702010-09-10 15:09:54 -0700462 if (null == mBluetoothService.getPendingOutgoingBonding()) {
463 mBluetoothService.setBondState(address, BluetoothDevice.BOND_BONDED);
Henrik Backlund42264152010-08-30 11:59:42 +0200464 }
Jaikumar Ganesh9488cbd2009-08-03 17:17:37 -0700465 } else {
Jaikumar Ganesha224f702010-09-10 15:09:54 -0700466 mBluetoothService.setBondState(address, BluetoothDevice.BOND_NONE);
Lixin Yueefa1dd72009-08-31 15:55:13 +0800467 mBluetoothService.setRemoteDeviceProperty(address, "Trusted", "false");
Jaikumar Ganesh9488cbd2009-08-03 17:17:37 -0700468 }
Lixin Yueefa1dd72009-08-31 15:55:13 +0800469 } else if (name.equals("Trusted")) {
470 if (DBG)
Jake Hamby9a62c9c2010-12-09 14:47:57 -0800471 log("set trust state succeeded, value is: " + propValues[1]);
Lixin Yueefa1dd72009-08-31 15:55:13 +0800472 mBluetoothService.setRemoteDeviceProperty(address, name, propValues[1]);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700473 }
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700474 }
475
Jake Hamby9a62c9c2010-12-09 14:47:57 -0800476 /**
477 * Called by native code on a PropertyChanged signal from
478 * org.bluez.Input.
479 *
480 * @param path the object path for the changed input device
481 * @param propValues a string array containing the key and one or more
482 * values.
483 */
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700484 private void onInputDevicePropertyChanged(String path, String[] propValues) {
485 String address = mBluetoothService.getAddressFromObjectPath(path);
486 if (address == null) {
Jake Hamby9a62c9c2010-12-09 14:47:57 -0800487 Log.e(TAG, "onInputDevicePropertyChanged: Address of the remote device is null");
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700488 return;
489 }
Jake Hamby9a62c9c2010-12-09 14:47:57 -0800490 log("Input Device : Name of Property is: " + propValues[0]);
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700491 boolean state = false;
492 if (propValues[1].equals("true")) {
493 state = true;
494 }
495 mBluetoothService.handleInputDevicePropertyChange(address, state);
496 }
497
Jake Hamby9a62c9c2010-12-09 14:47:57 -0800498 /**
499 * Called by native code on a PropertyChanged signal from
500 * org.bluez.Network.
501 *
502 * @param deviceObjectPath the object path for the changed PAN device
503 * @param propValues a string array containing the key and one or more
504 * values.
505 */
Danica Chang6fdd0c62010-08-11 14:54:43 -0700506 private void onPanDevicePropertyChanged(String deviceObjectPath, String[] propValues) {
507 String name = propValues[0];
508 String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath);
509 if (address == null) {
510 Log.e(TAG, "onPanDevicePropertyChanged: Address of the remote device in null");
511 return;
512 }
513 if (DBG) {
514 log("Pan Device property changed: " + address + " property: "
515 + name + " value: "+ propValues[1]);
516 }
517 BluetoothDevice device = mAdapter.getRemoteDevice(address);
518 if (name.equals("Connected")) {
Jaikumar Ganesh707952e2010-09-13 19:04:54 -0700519 if (propValues[1].equals("false")) {
520 mBluetoothService.handlePanDeviceStateChange(device,
Jaikumar Ganesh5200c8a2010-12-14 14:26:46 -0800521 BluetoothPan.STATE_DISCONNECTED,
522 BluetoothPan.LOCAL_PANU_ROLE);
Jaikumar Ganesh707952e2010-09-13 19:04:54 -0700523 }
524 } else if (name.equals("Interface")) {
525 String iface = propValues[1];
Jaikumar Ganesh057898a2010-12-21 22:42:04 -0800526 if (!iface.equals("")) {
527 mBluetoothService.handlePanDeviceStateChange(device, iface,
528 BluetoothPan.STATE_CONNECTED,
529 BluetoothPan.LOCAL_PANU_ROLE);
530 }
Danica Chang6fdd0c62010-08-11 14:54:43 -0700531 }
532 }
533
Jaikumar Ganeshb0eca412009-07-16 18:26:28 -0700534 private String checkPairingRequestAndGetAddress(String objectPath, int nativeData) {
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700535 String address = mBluetoothService.getAddressFromObjectPath(objectPath);
536 if (address == null) {
Jaikumar Ganeshb0eca412009-07-16 18:26:28 -0700537 Log.e(TAG, "Unable to get device address in checkPairingRequestAndGetAddress, " +
538 "returning null");
539 return null;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700540 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800541 address = address.toUpperCase();
542 mPasskeyAgentRequestData.put(address, new Integer(nativeData));
543
Nick Pellyde893f52009-09-08 13:15:33 -0700544 if (mBluetoothService.getBluetoothState() == BluetoothAdapter.STATE_TURNING_OFF) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700545 // shutdown path
Jaikumar Ganeshb0eca412009-07-16 18:26:28 -0700546 mBluetoothService.cancelPairingUserInput(address);
547 return null;
The Android Open Source Project10592532009-03-18 17:39:46 -0700548 }
Jaikumar Ganesh37686062009-09-30 13:57:37 -0700549 // Set state to BONDING. For incoming connections it will be set here.
550 // For outgoing connections, it gets set when we call createBond.
551 // Also set it only when the state is not already Bonded, we can sometimes
552 // get an authorization request from the remote end if it doesn't have the link key
553 // while we still have it.
Jaikumar Ganesha224f702010-09-10 15:09:54 -0700554 if (mBluetoothService.getBondState(address) != BluetoothDevice.BOND_BONDED)
555 mBluetoothService.setBondState(address, BluetoothDevice.BOND_BONDING);
Jaikumar Ganeshb0eca412009-07-16 18:26:28 -0700556 return address;
557 }
558
Jake Hamby9a62c9c2010-12-09 14:47:57 -0800559 /**
560 * Called by native code on a RequestPairingConsent method call to
561 * org.bluez.Agent.
562 *
563 * @param objectPath the path of the device to request pairing consent for
564 * @param nativeData a native pointer to the original D-Bus message
565 */
Jaikumar Ganesh32d85712009-09-10 22:00:05 -0700566 private void onRequestPairingConsent(String objectPath, int nativeData) {
567 String address = checkPairingRequestAndGetAddress(objectPath, nativeData);
568 if (address == null) return;
569
570 /* The link key will not be stored if the incoming request has MITM
571 * protection switched on. Unfortunately, some devices have MITM
572 * switched on even though their capabilities are NoInputNoOutput,
573 * so we may get this request many times. Also if we respond immediately,
574 * the other end is unable to handle it. Delay sending the message.
575 */
Jaikumar Ganesha224f702010-09-10 15:09:54 -0700576 if (mBluetoothService.getBondState(address) == BluetoothDevice.BOND_BONDED) {
Jaikumar Ganesh32d85712009-09-10 22:00:05 -0700577 Message message = mHandler.obtainMessage(EVENT_PAIRING_CONSENT_DELAYED_ACCEPT);
578 message.obj = address;
579 mHandler.sendMessageDelayed(message, 1500);
580 return;
581 }
Bheemsen Kulkarniabf99432010-03-17 14:56:00 +0530582 // Acquire wakelock during PIN code request to bring up LCD display
583 mWakeLock.acquire();
Jaikumar Ganesh32d85712009-09-10 22:00:05 -0700584 Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
585 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
586 intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
587 BluetoothDevice.PAIRING_VARIANT_CONSENT);
588 mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
Jake Hamby9a62c9c2010-12-09 14:47:57 -0800589 // Release wakelock to allow the LCD to go off after the PIN popup notification.
Bheemsen Kulkarniabf99432010-03-17 14:56:00 +0530590 mWakeLock.release();
Jaikumar Ganesh32d85712009-09-10 22:00:05 -0700591 return;
592 }
593
Jake Hamby9a62c9c2010-12-09 14:47:57 -0800594 /**
595 * Called by native code on a RequestConfirmation method call to
596 * org.bluez.Agent.
597 *
598 * @param objectPath the path of the device to confirm the passkey for
599 * @param passkey an integer containing the 6-digit passkey to confirm
600 * @param nativeData a native pointer to the original D-Bus message
601 */
Jaikumar Ganesh32d85712009-09-10 22:00:05 -0700602 private void onRequestPasskeyConfirmation(String objectPath, int passkey, int nativeData) {
Jaikumar Ganeshb0eca412009-07-16 18:26:28 -0700603 String address = checkPairingRequestAndGetAddress(objectPath, nativeData);
604 if (address == null) return;
Bheemsen Kulkarniabf99432010-03-17 14:56:00 +0530605 // Acquire wakelock during PIN code request to bring up LCD display
606 mWakeLock.acquire();
Nick Pelly005b2282009-09-10 10:21:56 -0700607 Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
608 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
Jaikumar Ganeshc88b0c62011-01-05 13:49:00 -0800609 intent.putExtra(BluetoothDevice.EXTRA_PAIRING_KEY, passkey);
Nick Pelly005b2282009-09-10 10:21:56 -0700610 intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
Jaikumar Ganesh32d85712009-09-10 22:00:05 -0700611 BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION);
Jaikumar Ganeshb0eca412009-07-16 18:26:28 -0700612 mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
Jake Hamby9a62c9c2010-12-09 14:47:57 -0800613 // Release wakelock to allow the LCD to go off after the PIN popup notification.
Bheemsen Kulkarniabf99432010-03-17 14:56:00 +0530614 mWakeLock.release();
Jaikumar Ganeshb0eca412009-07-16 18:26:28 -0700615 return;
616 }
617
Jake Hamby9a62c9c2010-12-09 14:47:57 -0800618 /**
619 * Called by native code on a RequestPasskey method call to
620 * org.bluez.Agent.
621 *
622 * @param objectPath the path of the device requesting a passkey
623 * @param nativeData a native pointer to the original D-Bus message
624 */
Jaikumar Ganeshb0eca412009-07-16 18:26:28 -0700625 private void onRequestPasskey(String objectPath, int nativeData) {
626 String address = checkPairingRequestAndGetAddress(objectPath, nativeData);
627 if (address == null) return;
Bheemsen Kulkarniabf99432010-03-17 14:56:00 +0530628 // Acquire wakelock during PIN code request to bring up LCD display
629 mWakeLock.acquire();
Nick Pelly005b2282009-09-10 10:21:56 -0700630 Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
631 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
632 intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
633 BluetoothDevice.PAIRING_VARIANT_PASSKEY);
Jaikumar Ganeshb0eca412009-07-16 18:26:28 -0700634 mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
Jake Hamby9a62c9c2010-12-09 14:47:57 -0800635 // Release wakelock to allow the LCD to go off after the PIN popup notification.
Bheemsen Kulkarniabf99432010-03-17 14:56:00 +0530636 mWakeLock.release();
Jaikumar Ganeshb0eca412009-07-16 18:26:28 -0700637 return;
638 }
639
Jake Hamby9a62c9c2010-12-09 14:47:57 -0800640 /**
641 * Called by native code on a RequestPinCode method call to
642 * org.bluez.Agent.
643 *
644 * @param objectPath the path of the device requesting a PIN code
645 * @param nativeData a native pointer to the original D-Bus message
646 */
Jaikumar Ganeshb0eca412009-07-16 18:26:28 -0700647 private void onRequestPinCode(String objectPath, int nativeData) {
648 String address = checkPairingRequestAndGetAddress(objectPath, nativeData);
649 if (address == null) return;
The Android Open Source Project10592532009-03-18 17:39:46 -0700650
Jaikumar Ganesh20923612009-09-20 12:56:21 -0700651 String pendingOutgoingAddress =
Jaikumar Ganesha224f702010-09-10 15:09:54 -0700652 mBluetoothService.getPendingOutgoingBonding();
Jaikumar Ganeshc88b0c62011-01-05 13:49:00 -0800653 BluetoothClass btClass = new BluetoothClass(mBluetoothService.getRemoteClass(address));
654 int btDeviceClass = btClass.getDeviceClass();
655
Jaikumar Ganesh20923612009-09-20 12:56:21 -0700656 if (address.equals(pendingOutgoingAddress)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800657 // we initiated the bonding
Jaikumar Ganesh3fbf7b62009-12-02 17:28:38 -0800658
659 // Check if its a dock
660 if (mBluetoothService.isBluetoothDock(address)) {
661 String pin = mBluetoothService.getDockPin();
662 mBluetoothService.setPin(address, BluetoothDevice.convertPinToBytes(pin));
663 return;
664 }
665
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800666 // try 0000 once if the device looks dumb
Jaikumar Ganeshc88b0c62011-01-05 13:49:00 -0800667 switch (btDeviceClass) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800668 case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
669 case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
670 case BluetoothClass.Device.AUDIO_VIDEO_HEADPHONES:
671 case BluetoothClass.Device.AUDIO_VIDEO_PORTABLE_AUDIO:
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800672 case BluetoothClass.Device.AUDIO_VIDEO_HIFI_AUDIO:
Jaikumar Ganesha224f702010-09-10 15:09:54 -0700673 if (mBluetoothService.attemptAutoPair(address)) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800674 }
675 }
Jaikumar Ganeshc88b0c62011-01-05 13:49:00 -0800676
Jaikumar Ganeshac6f13d2011-01-12 10:08:57 -0800677 if (btDeviceClass == BluetoothClass.Device.PERIPHERAL_KEYBOARD ||
678 btDeviceClass == BluetoothClass.Device.PERIPHERAL_KEYBOARD_POINTING) {
679 // Its a keyboard. Follow the HID spec recommendation of creating the
Jaikumar Ganeshf487d722011-01-12 10:12:01 -0800680 // passkey and displaying it to the user. If the keyboard doesn't follow
681 // the spec recommendation, check if the keyboard has a fixed PIN zero
682 // and pair.
683 if (mBluetoothService.isFixedPinZerosAutoPairKeyboard(address)) {
684 mBluetoothService.setPin(address, BluetoothDevice.convertPinToBytes("0000"));
685 return;
686 }
687
Jaikumar Ganeshac6f13d2011-01-12 10:08:57 -0800688 // Generate a variable PIN. This is not truly random but good enough.
689 int pin = (int) Math.floor(Math.random() * 10000);
690 sendDisplayPinIntent(address, pin);
691 return;
Jaikumar Ganeshc88b0c62011-01-05 13:49:00 -0800692 }
Bheemsen Kulkarniabf99432010-03-17 14:56:00 +0530693 // Acquire wakelock during PIN code request to bring up LCD display
694 mWakeLock.acquire();
Nick Pelly005b2282009-09-10 10:21:56 -0700695 Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
696 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
697 intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, BluetoothDevice.PAIRING_VARIANT_PIN);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800698 mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
Jake Hamby9a62c9c2010-12-09 14:47:57 -0800699 // Release wakelock to allow the LCD to go off after the PIN popup notification.
Bheemsen Kulkarniabf99432010-03-17 14:56:00 +0530700 mWakeLock.release();
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700701 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800702 }
703
Jake Hamby9a62c9c2010-12-09 14:47:57 -0800704 /**
705 * Called by native code on a DisplayPasskey method call to
706 * org.bluez.Agent.
707 *
708 * @param objectPath the path of the device to display the passkey for
709 * @param passkey an integer containing the 6-digit passkey
710 * @param nativeData a native pointer to the original D-Bus message
711 */
Jaikumar Ganesh32d85712009-09-10 22:00:05 -0700712 private void onDisplayPasskey(String objectPath, int passkey, int nativeData) {
713 String address = checkPairingRequestAndGetAddress(objectPath, nativeData);
714 if (address == null) return;
715
Bheemsen Kulkarniabf99432010-03-17 14:56:00 +0530716 // Acquire wakelock during PIN code request to bring up LCD display
717 mWakeLock.acquire();
Jaikumar Ganesh32d85712009-09-10 22:00:05 -0700718 Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
719 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
Jaikumar Ganeshc88b0c62011-01-05 13:49:00 -0800720 intent.putExtra(BluetoothDevice.EXTRA_PAIRING_KEY, passkey);
Jaikumar Ganesh32d85712009-09-10 22:00:05 -0700721 intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
722 BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY);
723 mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
Jake Hamby9a62c9c2010-12-09 14:47:57 -0800724 //Release wakelock to allow the LCD to go off after the PIN popup notification.
Bheemsen Kulkarniabf99432010-03-17 14:56:00 +0530725 mWakeLock.release();
Jaikumar Ganesh32d85712009-09-10 22:00:05 -0700726 }
727
Jaikumar Ganeshc88b0c62011-01-05 13:49:00 -0800728 private void sendDisplayPinIntent(String address, int pin) {
729 // Acquire wakelock during PIN code request to bring up LCD display
730 mWakeLock.acquire();
731 Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
732 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
733 intent.putExtra(BluetoothDevice.EXTRA_PAIRING_KEY, pin);
734 intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
735 BluetoothDevice.PAIRING_VARIANT_DISPLAY_PIN);
736 mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
737 //Release wakelock to allow the LCD to go off after the PIN popup notifcation.
738 mWakeLock.release();
739 }
740
Jake Hamby9a62c9c2010-12-09 14:47:57 -0800741 /**
742 * Called by native code on a RequestOobData method call to
743 * org.bluez.Agent.
744 *
745 * @param objectPath the path of the device requesting OOB data
746 * @param nativeData a native pointer to the original D-Bus message
747 */
748 private void onRequestOobData(String objectPath, int nativeData) {
Jaikumar Ganeshcc5494c2010-09-09 15:37:57 -0700749 String address = checkPairingRequestAndGetAddress(objectPath, nativeData);
750 if (address == null) return;
751
752 Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
753 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
754 intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
755 BluetoothDevice.PAIRING_VARIANT_OOB_CONSENT);
756 mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
757 }
758
Jake Hamby9a62c9c2010-12-09 14:47:57 -0800759 /**
760 * Called by native code on an Authorize method call to org.bluez.Agent.
761 *
762 * @param objectPath the path of the device requesting to be authorized
763 * @param deviceUuid the UUID of the requesting device
Matthew Xiea0c68032011-06-25 21:47:07 -0700764 * @param nativeData reference for native data
Jake Hamby9a62c9c2010-12-09 14:47:57 -0800765 */
Matthew Xiea0c68032011-06-25 21:47:07 -0700766 private void onAgentAuthorize(String objectPath, String deviceUuid, int nativeData) {
767 if (!mBluetoothService.isEnabled()) return;
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700768
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700769 String address = mBluetoothService.getAddressFromObjectPath(objectPath);
770 if (address == null) {
771 Log.e(TAG, "Unable to get device address in onAuthAgentAuthorize");
Matthew Xiea0c68032011-06-25 21:47:07 -0700772 return;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700773 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800774
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800775 boolean authorized = false;
Jaikumar Ganeshdd0463a2009-09-16 12:30:02 -0700776 ParcelUuid uuid = ParcelUuid.fromString(deviceUuid);
Matthew Xiea0c68032011-06-25 21:47:07 -0700777
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700778 BluetoothDevice device = mAdapter.getRemoteDevice(address);
Matthew Xiea0c68032011-06-25 21:47:07 -0700779 mAuthorizationAgentRequestData.put(address, new Integer(nativeData));
Jaikumar Ganeshb16c4f72009-12-04 15:10:54 -0800780
Nick Pellyb23d4452009-08-26 09:33:40 -0700781 // Bluez sends the UUID of the local service being accessed, _not_ the
782 // remote service
Jaikumar Ganesh96a79832010-09-27 17:02:01 -0700783 if (mA2dp != null &&
784 (BluetoothUuid.isAudioSource(uuid) || BluetoothUuid.isAvrcpTarget(uuid)
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700785 || BluetoothUuid.isAdvAudioDist(uuid)) &&
Jaikumar Ganesh96a79832010-09-27 17:02:01 -0700786 !isOtherSinkInNonDisconnectedState(address)) {
787 authorized = mA2dp.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
Matthew Xiea0c68032011-06-25 21:47:07 -0700788 if (authorized && !BluetoothUuid.isAvrcpTarget(uuid)) {
789 Log.i(TAG, "First check pass for incoming A2DP / AVRCP connection from " + address);
Jaikumar Ganesh70a053b2010-10-13 15:54:30 -0700790 // Some headsets try to connect AVCTP before AVDTP - against the recommendation
791 // If AVCTP connection fails, we get stuck in IncomingA2DP state in the state
792 // machine. We don't handle AVCTP signals currently. We only send
793 // intents for AVDTP state changes. We need to handle both of them in
794 // some cases. For now, just don't move to incoming state in this case.
Matthew Xiea0c68032011-06-25 21:47:07 -0700795 mBluetoothService.notifyIncomingA2dpConnection(address);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800796 } else {
Matthew Xiea0c68032011-06-25 21:47:07 -0700797 Log.i(TAG, "" + authorized +
798 "Incoming A2DP / AVRCP connection from " + address);
799 mA2dp.allowIncomingConnect(device, authorized);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800800 }
Jaikumar Ganeshbbd86752011-08-01 19:11:18 -0700801 } else if (BluetoothUuid.isInputDevice(uuid)) {
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800802 // We can have more than 1 input device connected.
Jaikumar Ganeshbbd86752011-08-01 19:11:18 -0700803 authorized = mBluetoothService.getInputDevicePriority(device) >
804 BluetoothInputDevice.PRIORITY_OFF;
805 if (authorized) {
806 Log.i(TAG, "First check pass for incoming HID connection from " + address);
807 // notify profile state change
808 mBluetoothService.notifyIncomingHidConnection(address);
809 } else {
810 Log.i(TAG, "Rejecting incoming HID connection from " + address);
811 mBluetoothService.allowIncomingProfileConnect(device, authorized);
812 }
813 } else if (BluetoothUuid.isBnep(uuid)) {
814 // PAN doesn't go to the state machine, accept or reject from here
815 authorized = mBluetoothService.allowIncomingTethering();
816 mBluetoothService.allowIncomingProfileConnect(device, authorized);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800817 } else {
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700818 Log.i(TAG, "Rejecting incoming " + deviceUuid + " connection from " + address);
Jaikumar Ganeshbbd86752011-08-01 19:11:18 -0700819 mBluetoothService.allowIncomingProfileConnect(device, authorized);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800820 }
Nick Pellyb23d4452009-08-26 09:33:40 -0700821 log("onAgentAuthorize(" + objectPath + ", " + deviceUuid + ") = " + authorized);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800822 }
823
Jaikumar Ganeshcc5494c2010-09-09 15:37:57 -0700824 private boolean onAgentOutOfBandDataAvailable(String objectPath) {
825 if (!mBluetoothService.isEnabled()) return false;
826
827 String address = mBluetoothService.getAddressFromObjectPath(objectPath);
828 if (address == null) return false;
829
830 if (mBluetoothService.getDeviceOutOfBandData(
831 mAdapter.getRemoteDevice(address)) != null) {
832 return true;
833 }
Jaikumar Ganesh15107702010-09-13 15:24:01 -0700834 return false;
Jaikumar Ganeshcc5494c2010-09-09 15:37:57 -0700835 }
836
Jaikumar Ganesh96a79832010-09-27 17:02:01 -0700837 private boolean isOtherSinkInNonDisconnectedState(String address) {
Jaikumar Ganesh5a1e4cf2010-10-18 17:05:09 -0700838 List<BluetoothDevice> devices =
Jaikumar Ganesh96a79832010-09-27 17:02:01 -0700839 mA2dp.getDevicesMatchingConnectionStates(new int[] {BluetoothA2dp.STATE_CONNECTED,
840 BluetoothA2dp.STATE_CONNECTING,
841 BluetoothA2dp.STATE_DISCONNECTING});
842
Jaikumar Ganesh577dd1f2009-12-17 14:59:10 -0800843 if (devices.size() == 0) return false;
Jaikumar Ganesh5a1e4cf2010-10-18 17:05:09 -0700844 for (BluetoothDevice dev: devices) {
Jaikumar Ganesh577dd1f2009-12-17 14:59:10 -0800845 if (!dev.getAddress().equals(address)) return true;
846 }
847 return false;
848 }
849
Jake Hamby9a62c9c2010-12-09 14:47:57 -0800850 /**
851 * Called by native code on a Cancel method call to org.bluez.Agent.
852 */
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700853 private void onAgentCancel() {
Nick Pelly005b2282009-09-10 10:21:56 -0700854 Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_CANCEL);
Jaikumar Ganeshb0eca412009-07-16 18:26:28 -0700855 mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
Jaikumar Ganeshe5d93b72009-10-08 02:27:52 -0700856
857 mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_AGENT_CANCEL),
858 1500);
859
Jaikumar Ganeshb0eca412009-07-16 18:26:28 -0700860 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800861 }
862
Jake Hamby9a62c9c2010-12-09 14:47:57 -0800863 /**
864 * Called by native code for the async response to a DiscoverServices
865 * method call to org.bluez.Adapter.
866 *
867 * @param deviceObjectPath the path for the specified device
868 * @param result true for success; false on error
869 */
Jaikumar Ganesh1caa6d12009-09-18 11:32:54 -0700870 private void onDiscoverServicesResult(String deviceObjectPath, boolean result) {
871 String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath);
Staffan Lindvall81f8e3c2010-10-27 10:34:53 +0200872 if (address == null) return;
873
Jaikumar Ganesh1caa6d12009-09-18 11:32:54 -0700874 // We don't parse the xml here, instead just query Bluez for the properties.
875 if (result) {
Jaikumar Ganesh10eac972009-09-21 12:48:51 -0700876 mBluetoothService.updateRemoteDevicePropertiesCache(address);
Jaikumar Ganesh1caa6d12009-09-18 11:32:54 -0700877 }
878 mBluetoothService.sendUuidIntent(address);
Nick Pelly16fb88a2009-10-07 07:44:03 +0200879 mBluetoothService.makeServiceChannelCallbacks(address);
Jaikumar Ganesh1caa6d12009-09-18 11:32:54 -0700880 }
881
Jake Hamby9a62c9c2010-12-09 14:47:57 -0800882 /**
883 * Called by native code for the async response to a CreateDevice
884 * method call to org.bluez.Adapter.
885 *
886 * @param address the MAC address of the device to create
887 * @param result {@link #CREATE_DEVICE_SUCCESS},
888 * {@link #CREATE_DEVICE_ALREADY_EXISTS} or {@link #CREATE_DEVICE_FAILED}}
889 */
Nick Pelly16fb88a2009-10-07 07:44:03 +0200890 private void onCreateDeviceResult(String address, int result) {
891 if (DBG) log("Result of onCreateDeviceResult:" + result);
892
893 switch (result) {
894 case CREATE_DEVICE_ALREADY_EXISTS:
895 String path = mBluetoothService.getObjectPathFromAddress(address);
896 if (path != null) {
897 mBluetoothService.discoverServicesNative(path, "");
898 break;
899 }
Jake Hamby9a62c9c2010-12-09 14:47:57 -0800900 Log.w(TAG, "Device exists, but we don't have the bluez path, failing");
Nick Pelly16fb88a2009-10-07 07:44:03 +0200901 // fall-through
902 case CREATE_DEVICE_FAILED:
Jaikumar Ganesh1caa6d12009-09-18 11:32:54 -0700903 mBluetoothService.sendUuidIntent(address);
Nick Pelly16fb88a2009-10-07 07:44:03 +0200904 mBluetoothService.makeServiceChannelCallbacks(address);
905 break;
906 case CREATE_DEVICE_SUCCESS:
907 // nothing to do, UUID intent's will be sent via property changed
Jaikumar Ganesh1caa6d12009-09-18 11:32:54 -0700908 }
909 }
910
Jake Hamby9a62c9c2010-12-09 14:47:57 -0800911 /**
912 * Called by native code for the async response to a Connect
913 * method call to org.bluez.Input.
914 *
915 * @param path the path of the specified input device
916 * @param result Result code of the operation.
917 */
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -0800918 private void onInputDeviceConnectionResult(String path, int result) {
Jaikumar Ganeshde075032010-07-19 16:28:27 -0700919 // Success case gets handled by Property Change signal
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -0800920 if (result != BluetoothInputDevice.INPUT_OPERATION_SUCCESS) {
Jaikumar Ganeshde075032010-07-19 16:28:27 -0700921 String address = mBluetoothService.getAddressFromObjectPath(path);
922 if (address == null) return;
923
924 boolean connected = false;
925 BluetoothDevice device = mAdapter.getRemoteDevice(address);
Jaikumar Ganesh4ab0e772011-02-18 14:52:32 -0800926 int state = mBluetoothService.getInputDeviceConnectionState(device);
Jaikumar Ganeshde075032010-07-19 16:28:27 -0700927 if (state == BluetoothInputDevice.STATE_CONNECTING) {
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -0800928 if (result == BluetoothInputDevice.INPUT_CONNECT_FAILED_ALREADY_CONNECTED) {
929 connected = true;
930 } else {
931 connected = false;
932 }
Jaikumar Ganeshde075032010-07-19 16:28:27 -0700933 } else if (state == BluetoothInputDevice.STATE_DISCONNECTING) {
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -0800934 if (result == BluetoothInputDevice.INPUT_DISCONNECT_FAILED_NOT_CONNECTED) {
935 connected = false;
936 } else {
937 // There is no better way to handle this, this shouldn't happen
938 connected = true;
939 }
Jaikumar Ganeshde075032010-07-19 16:28:27 -0700940 } else {
941 Log.e(TAG, "Error onInputDeviceConnectionResult. State is:" + state);
942 }
943 mBluetoothService.handleInputDevicePropertyChange(address, connected);
944 }
945 }
946
Jake Hamby9a62c9c2010-12-09 14:47:57 -0800947 /**
948 * Called by native code for the async response to a Connect
949 * method call to org.bluez.Network.
950 *
951 * @param path the path of the specified PAN device
952 * @param result Result code of the operation.
953 */
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -0800954 private void onPanDeviceConnectionResult(String path, int result) {
Danica Chang6fdd0c62010-08-11 14:54:43 -0700955 log ("onPanDeviceConnectionResult " + path + " " + result);
956 // Success case gets handled by Property Change signal
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -0800957 if (result != BluetoothPan.PAN_OPERATION_SUCCESS) {
Danica Chang6fdd0c62010-08-11 14:54:43 -0700958 String address = mBluetoothService.getAddressFromObjectPath(path);
959 if (address == null) return;
960
961 boolean connected = false;
962 BluetoothDevice device = mAdapter.getRemoteDevice(address);
Jaikumar Ganesh74ef1192011-02-23 10:22:15 -0800963 int state = mBluetoothService.getPanDeviceConnectionState(device);
Danica Chang6fdd0c62010-08-11 14:54:43 -0700964 if (state == BluetoothPan.STATE_CONNECTING) {
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -0800965 if (result == BluetoothPan.PAN_CONNECT_FAILED_ALREADY_CONNECTED) {
966 connected = true;
967 } else {
968 connected = false;
969 }
Danica Chang6fdd0c62010-08-11 14:54:43 -0700970 } else if (state == BluetoothPan.STATE_DISCONNECTING) {
Jaikumar Ganeshfbe807d2011-01-19 13:59:32 -0800971 if (result == BluetoothPan.PAN_DISCONNECT_FAILED_NOT_CONNECTED) {
972 connected = false;
973 } else {
974 // There is no better way to handle this, this shouldn't happen
975 connected = true;
976 }
Danica Chang6fdd0c62010-08-11 14:54:43 -0700977 } else {
978 Log.e(TAG, "Error onPanDeviceConnectionResult. State is: "
979 + state + " result: "+ result);
980 }
981 int newState = connected? BluetoothPan.STATE_CONNECTED :
982 BluetoothPan.STATE_DISCONNECTED;
Jaikumar Ganesh5200c8a2010-12-14 14:26:46 -0800983 mBluetoothService.handlePanDeviceStateChange(device, newState,
984 BluetoothPan.LOCAL_PANU_ROLE);
Danica Chang6fdd0c62010-08-11 14:54:43 -0700985 }
986 }
987
Jake Hamby9a62c9c2010-12-09 14:47:57 -0800988 /**
989 * Called by native code on a DeviceDisconnected signal from
990 * org.bluez.NetworkServer.
991 *
992 * @param address the MAC address of the disconnected device
993 */
Jaikumar Ganeshc1520ec2010-08-31 19:55:10 -0700994 private void onNetworkDeviceDisconnected(String address) {
995 BluetoothDevice device = mAdapter.getRemoteDevice(address);
Jaikumar Ganesh5200c8a2010-12-14 14:26:46 -0800996 mBluetoothService.handlePanDeviceStateChange(device, BluetoothPan.STATE_DISCONNECTED,
997 BluetoothPan.LOCAL_NAP_ROLE);
Jaikumar Ganeshc1520ec2010-08-31 19:55:10 -0700998 }
999
Jake Hamby9a62c9c2010-12-09 14:47:57 -08001000 /**
1001 * Called by native code on a DeviceConnected signal from
1002 * org.bluez.NetworkServer.
1003 *
1004 * @param address the MAC address of the connected device
1005 * @param iface interface of remote network
1006 * @param destUuid unused UUID parameter
1007 */
Jaikumar Ganesh707952e2010-09-13 19:04:54 -07001008 private void onNetworkDeviceConnected(String address, String iface, int destUuid) {
Jaikumar Ganeshc1520ec2010-08-31 19:55:10 -07001009 BluetoothDevice device = mAdapter.getRemoteDevice(address);
Jaikumar Ganesh5200c8a2010-12-14 14:26:46 -08001010 mBluetoothService.handlePanDeviceStateChange(device, iface, BluetoothPan.STATE_CONNECTED,
1011 BluetoothPan.LOCAL_NAP_ROLE);
Jaikumar Ganeshc1520ec2010-08-31 19:55:10 -07001012 }
1013
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -07001014 /**
1015 * Called by native code on a PropertyChanged signal from
1016 * org.bluez.HealthDevice.
1017 *
1018 * @param devicePath the object path of the remote device
1019 * @param propValues Properties (Name-Value) of the Health Device.
1020 */
1021 private void onHealthDevicePropertyChanged(String devicePath, String[] propValues) {
1022 log("Health Device : Name of Property is: " + propValues[0] + " Value:" + propValues[1]);
1023 mBluetoothService.onHealthDevicePropertyChanged(devicePath, propValues[1]);
1024 }
1025
1026 /**
1027 * Called by native code on a ChannelCreated/Deleted signal from
1028 * org.bluez.HealthDevice.
1029 *
1030 * @param devicePath the object path of the remote device
1031 * @param channelPath the path of the health channel.
1032 * @param exists Boolean to indicate if the channel was created or deleted.
1033 */
1034 private void onHealthDeviceChannelChanged(String devicePath, String channelPath,
1035 boolean exists) {
1036 log("Health Device : devicePath: " + devicePath + ":channelPath:" + channelPath +
1037 ":exists" + exists);
1038 mBluetoothService.onHealthDeviceChannelChanged(devicePath, channelPath, exists);
1039 }
1040
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001041 private void onRestartRequired() {
1042 if (mBluetoothService.isEnabled()) {
Jake Hambyf51eada2010-09-21 13:39:53 -07001043 Log.e(TAG, "*** A serious error occurred (did bluetoothd crash?) - " +
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -07001044 "restarting Bluetooth ***");
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -07001045 mHandler.sendEmptyMessage(EVENT_RESTART_BLUETOOTH);
1046 }
1047 }
1048
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001049 private static void log(String msg) {
1050 Log.d(TAG, msg);
1051 }
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -07001052
1053 private native void initializeNativeDataNative();
1054 private native void startEventLoopNative();
1055 private native void stopEventLoopNative();
1056 private native boolean isEventLoopRunningNative();
1057 private native void cleanupNativeDataNative();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001058}