blob: 9f36f7ee666e2c32f90607dd5f07c88ba2788df9 [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;
20import android.bluetooth.BluetoothClass;
Nick Pellybd022f42009-08-14 18:33:38 -070021import android.bluetooth.BluetoothAdapter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022import android.bluetooth.BluetoothDevice;
23import android.bluetooth.BluetoothError;
24import android.bluetooth.BluetoothIntent;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -070025import android.bluetooth.BluetoothUuid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080026import android.content.Context;
27import android.content.Intent;
28import android.os.Handler;
29import android.os.Message;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080030import android.util.Log;
31
32import java.util.HashMap;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -070033import java.util.UUID;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034
35/**
36 * TODO: Move this to
37 * java/services/com/android/server/BluetoothEventLoop.java
38 * and make the contructor package private again.
39 *
40 * @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;
Nick Pellybd022f42009-08-14 18:33:38 -070052 private final BluetoothService mBluetoothService;
53 private final BluetoothAdapter mAdapter;
The Android Open Source Project10592532009-03-18 17:39:46 -070054 private final Context mContext;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055
56 private static final int EVENT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 1;
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -070057 private static final int EVENT_RESTART_BLUETOOTH = 2;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058
59 // The time (in millisecs) to delay the pairing attempt after the first
60 // auto pairing attempt fails. We use an exponential delay with
61 // INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY as the initial value and
62 // MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY as the max value.
63 private static final long INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 3000;
64 private static final long MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 12000;
65
66 private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
67 private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
68
69 private final Handler mHandler = new Handler() {
70 @Override
71 public void handleMessage(Message msg) {
72 switch (msg.what) {
73 case EVENT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY:
74 String address = (String)msg.obj;
75 if (address != null) {
76 mBluetoothService.createBond(address);
77 return;
78 }
79 break;
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -070080 case EVENT_RESTART_BLUETOOTH:
Nick Pelly37b5a102009-03-24 20:46:18 -070081 mBluetoothService.restart();
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -070082 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080083 }
84 }
85 };
86
87 static { classInitNative(); }
88 private static native void classInitNative();
89
Nick Pellybd022f42009-08-14 18:33:38 -070090 /* pacakge */ BluetoothEventLoop(Context context, BluetoothAdapter adapter,
91 BluetoothService bluetoothService) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092 mBluetoothService = bluetoothService;
93 mContext = context;
94 mPasskeyAgentRequestData = new HashMap();
Nick Pellybd022f42009-08-14 18:33:38 -070095 mAdapter = adapter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080096 initializeNativeDataNative();
97 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080098
99 protected void finalize() throws Throwable {
100 try {
101 cleanupNativeDataNative();
102 } finally {
103 super.finalize();
104 }
105 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700107 /* package */ HashMap<String, Integer> getPasskeyAgentRequestData() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108 return mPasskeyAgentRequestData;
109 }
110
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700111 /* package */ void start() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800112
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700113 if (!isEventLoopRunningNative()) {
114 if (DBG) log("Starting Event Loop thread");
115 startEventLoopNative();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800116 }
117 }
118
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700119 public void stop() {
120 if (isEventLoopRunningNative()) {
121 if (DBG) log("Stopping Event Loop thread");
122 stopEventLoopNative();
123 }
124 }
125
126 public boolean isEventLoopRunning() {
127 return isEventLoopRunningNative();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800128 }
129
Jaikumar Ganesh9488cbd2009-08-03 17:17:37 -0700130 private void addDevice(String address, String[] properties) {
131 mBluetoothService.addRemoteDeviceProperties(address, properties);
132 String rssi = mBluetoothService.getRemoteDeviceProperty(address, "RSSI");
133 String classValue = mBluetoothService.getRemoteDeviceProperty(address, "Class");
134 String name = mBluetoothService.getRemoteDeviceProperty(address, "Name");
135 short rssiValue;
136 // For incoming connections, we don't get the RSSI value. Use a default of MIN_VALUE.
137 // If we accept the pairing, we will automatically show it at the top of the list.
138 if (rssi != null) {
139 rssiValue = (short)Integer.valueOf(rssi).intValue();
140 } else {
141 rssiValue = Short.MIN_VALUE;
142 }
143 if (classValue != null) {
144 Intent intent = new Intent(BluetoothIntent.REMOTE_DEVICE_FOUND_ACTION);
Nick Pellybd022f42009-08-14 18:33:38 -0700145 intent.putExtra(BluetoothIntent.DEVICE, mAdapter.getRemoteDevice(address));
Jaikumar Ganesh9488cbd2009-08-03 17:17:37 -0700146 intent.putExtra(BluetoothIntent.CLASS, Integer.valueOf(classValue));
147 intent.putExtra(BluetoothIntent.RSSI, rssiValue);
148 intent.putExtra(BluetoothIntent.NAME, name);
149
150 mContext.sendBroadcast(intent, BLUETOOTH_PERM);
151 } else {
152 log ("ClassValue: " + classValue + " for remote device: " + address + " is null");
153 }
154 }
155
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700156 private void onDeviceFound(String address, String[] properties) {
157 if (properties == null) {
158 Log.e(TAG, "ERROR: Remote device properties are null");
159 return;
160 }
Jaikumar Ganesh9488cbd2009-08-03 17:17:37 -0700161 addDevice(address, properties);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800162 }
163
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700164 private void onDeviceDisappeared(String address) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800165 Intent intent = new Intent(BluetoothIntent.REMOTE_DEVICE_DISAPPEARED_ACTION);
Nick Pellybd022f42009-08-14 18:33:38 -0700166 intent.putExtra(BluetoothIntent.DEVICE, mAdapter.getRemoteDevice(address));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800167 mContext.sendBroadcast(intent, BLUETOOTH_PERM);
168 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800169
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700170 private void onCreatePairedDeviceResult(String address, int result) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800171 address = address.toUpperCase();
172 if (result == BluetoothError.SUCCESS) {
173 mBluetoothService.getBondState().setBondState(address, BluetoothDevice.BOND_BONDED);
174 if (mBluetoothService.getBondState().isAutoPairingAttemptsInProgress(address)) {
175 mBluetoothService.getBondState().clearPinAttempts(address);
176 }
177 } else if (result == BluetoothDevice.UNBOND_REASON_AUTH_FAILED &&
178 mBluetoothService.getBondState().getAttempt(address) == 1) {
179 mBluetoothService.getBondState().addAutoPairingFailure(address);
180 pairingAttempt(address, result);
181 } else if (result == BluetoothDevice.UNBOND_REASON_REMOTE_DEVICE_DOWN &&
182 mBluetoothService.getBondState().isAutoPairingAttemptsInProgress(address)) {
183 pairingAttempt(address, result);
184 } else {
185 mBluetoothService.getBondState().setBondState(address,
186 BluetoothDevice.BOND_NOT_BONDED, result);
187 if (mBluetoothService.getBondState().isAutoPairingAttemptsInProgress(address)) {
188 mBluetoothService.getBondState().clearPinAttempts(address);
189 }
190 }
191 }
192
193 private void pairingAttempt(String address, int result) {
194 // This happens when our initial guess of "0000" as the pass key
195 // fails. Try to create the bond again and display the pin dialog
196 // to the user. Use back-off while posting the delayed
197 // message. The initial value is
198 // INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY and the max value is
199 // MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY. If the max value is
200 // reached, display an error to the user.
201 int attempt = mBluetoothService.getBondState().getAttempt(address);
202 if (attempt * INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY >
203 MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY) {
204 mBluetoothService.getBondState().clearPinAttempts(address);
205 mBluetoothService.getBondState().setBondState(address,
206 BluetoothDevice.BOND_NOT_BONDED, result);
207 return;
208 }
209
210 Message message = mHandler.obtainMessage(EVENT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY);
211 message.obj = address;
212 boolean postResult = mHandler.sendMessageDelayed(message,
213 attempt * INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY);
214 if (!postResult) {
215 mBluetoothService.getBondState().clearPinAttempts(address);
216 mBluetoothService.getBondState().setBondState(address,
217 BluetoothDevice.BOND_NOT_BONDED, result);
218 return;
219 }
220 mBluetoothService.getBondState().attempt(address);
221 }
222
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700223 private void onDeviceCreated(String deviceObjectPath) {
Jaikumar Ganesh9488cbd2009-08-03 17:17:37 -0700224 String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath);
225 if (!mBluetoothService.isRemoteDeviceInCache(address)) {
226 // Incoming connection, we haven't seen this device, add to cache.
227 String[] properties = mBluetoothService.getRemoteDeviceProperties(address);
228 if (properties != null) {
229 addDevice(address, properties);
230 }
231 }
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700232 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800233 }
234
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700235 private void onDeviceRemoved(String deviceObjectPath) {
236 String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath);
237 if (address != null)
238 mBluetoothService.getBondState().setBondState(address.toUpperCase(),
239 BluetoothDevice.BOND_NOT_BONDED, BluetoothDevice.UNBOND_REASON_REMOVED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800240 }
241
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700242 /*package*/ void onPropertyChanged(String[] propValues) {
Jaikumar Ganesh9519ce72009-09-08 21:37:32 -0700243 if (mBluetoothService.isAdapterPropertiesEmpty()) {
244 // We have got a property change before
245 // we filled up our cache.
246 mBluetoothService.getAllProperties();
247 }
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700248 String name = propValues[0];
249 if (name.equals("Name")) {
250 Intent intent = new Intent(BluetoothIntent.NAME_CHANGED_ACTION);
251 intent.putExtra(BluetoothIntent.NAME, propValues[1]);
252 mContext.sendBroadcast(intent, BLUETOOTH_PERM);
253 mBluetoothService.setProperty(name, propValues[1]);
254 } else if (name.equals("Pairable") || name.equals("Discoverable")) {
255 String pairable = name.equals("Pairable") ? propValues[1] :
256 mBluetoothService.getProperty("Pairable");
257 String discoverable = name.equals("Discoverable") ? propValues[1] :
258 mBluetoothService.getProperty("Discoverable");
259
260 // This shouldn't happen, unless Adapter Properties are null.
261 if (pairable == null || discoverable == null)
262 return;
263
Nick Pellybd022f42009-08-14 18:33:38 -0700264 int mode = BluetoothService.bluezStringToScanMode(
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700265 pairable.equals("true"),
266 discoverable.equals("true"));
267 if (mode >= 0) {
Nick Pellyde893f52009-09-08 13:15:33 -0700268 Intent intent = new Intent(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
269 intent.putExtra(BluetoothAdapter.EXTRA_SCAN_MODE, mode);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700270 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
271 mContext.sendBroadcast(intent, BLUETOOTH_PERM);
272 }
273 mBluetoothService.setProperty(name, propValues[1]);
274 } else if (name.equals("Discovering")) {
275 Intent intent;
276 if (propValues[1].equals("true")) {
277 mBluetoothService.setIsDiscovering(true);
278 intent = new Intent(BluetoothIntent.DISCOVERY_STARTED_ACTION);
279 } else {
280 // Stop the discovery.
281 mBluetoothService.cancelDiscovery();
282 mBluetoothService.setIsDiscovering(false);
283 intent = new Intent(BluetoothIntent.DISCOVERY_COMPLETED_ACTION);
284 }
285 mContext.sendBroadcast(intent, BLUETOOTH_PERM);
286 mBluetoothService.setProperty(name, propValues[1]);
287 } else if (name.equals("Devices")) {
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700288 String value = null;
289 int len = Integer.valueOf(propValues[1]);
290 if (len > 0) {
Jaikumar Ganeshefa33672009-08-28 13:48:55 -0700291 StringBuilder str = new StringBuilder();
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700292 for (int i = 2; i < propValues.length; i++) {
Jaikumar Ganeshefa33672009-08-28 13:48:55 -0700293 str.append(propValues[i]);
294 str.append(",");
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700295 }
Jaikumar Ganeshefa33672009-08-28 13:48:55 -0700296 value = str.toString();
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700297 }
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700298 mBluetoothService.setProperty(name, value);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700299 } else if (name.equals("Powered")) {
300 // bluetoothd has restarted, re-read all our properties.
301 // Note: bluez only sends this property change when it restarts.
302 if (propValues[1].equals("true"))
303 onRestartRequired();
304 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800305 }
306
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700307 private void onDevicePropertyChanged(String deviceObjectPath, String[] propValues) {
308 String name = propValues[0];
309 String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath);
310 if (address == null) {
311 Log.e(TAG, "onDevicePropertyChanged: Address of the remote device in null");
312 return;
313 }
Nick Pellybd022f42009-08-14 18:33:38 -0700314 BluetoothDevice device = mAdapter.getRemoteDevice(address);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700315 if (name.equals("Name")) {
316 Intent intent = new Intent(BluetoothIntent.REMOTE_NAME_UPDATED_ACTION);
Nick Pellybd022f42009-08-14 18:33:38 -0700317 intent.putExtra(BluetoothIntent.DEVICE, device);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700318 intent.putExtra(BluetoothIntent.NAME, propValues[1]);
319 mContext.sendBroadcast(intent, BLUETOOTH_PERM);
320 mBluetoothService.setRemoteDeviceProperty(address, name, propValues[1]);
321 } else if (name.equals("Class")) {
322 Intent intent = new Intent(BluetoothIntent.REMOTE_DEVICE_CLASS_UPDATED_ACTION);
Nick Pellybd022f42009-08-14 18:33:38 -0700323 intent.putExtra(BluetoothIntent.DEVICE, device);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700324 intent.putExtra(BluetoothIntent.CLASS, propValues[1]);
325 mContext.sendBroadcast(intent, BLUETOOTH_PERM);
326 mBluetoothService.setRemoteDeviceProperty(address, name, propValues[1]);
327 } else if (name.equals("Connected")) {
328 Intent intent = null;
329 if (propValues[1].equals("true")) {
330 intent = new Intent(BluetoothIntent.REMOTE_DEVICE_CONNECTED_ACTION);
331 } else {
332 intent = new Intent(BluetoothIntent.REMOTE_DEVICE_DISCONNECTED_ACTION);
333 }
Nick Pellybd022f42009-08-14 18:33:38 -0700334 intent.putExtra(BluetoothIntent.DEVICE, device);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700335 mContext.sendBroadcast(intent, BLUETOOTH_PERM);
336 mBluetoothService.setRemoteDeviceProperty(address, name, propValues[1]);
337 } else if (name.equals("UUIDs")) {
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700338 String uuid = null;
339 int len = Integer.valueOf(propValues[1]);
340 if (len > 0) {
Jaikumar Ganeshefa33672009-08-28 13:48:55 -0700341 StringBuilder str = new StringBuilder();
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700342 for (int i = 2; i < propValues.length; i++) {
Jaikumar Ganeshefa33672009-08-28 13:48:55 -0700343 str.append(propValues[i]);
344 str.append(",");
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700345 }
Jaikumar Ganeshefa33672009-08-28 13:48:55 -0700346 uuid = str.toString();
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700347 }
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700348 mBluetoothService.setRemoteDeviceProperty(address, name, uuid);
Jaikumar Ganesh9488cbd2009-08-03 17:17:37 -0700349 } else if (name.equals("Paired")) {
350 if (propValues[1].equals("true")) {
351 mBluetoothService.getBondState().setBondState(address, BluetoothDevice.BOND_BONDED);
352 } else {
353 mBluetoothService.getBondState().setBondState(address,
354 BluetoothDevice.BOND_NOT_BONDED);
Lixin Yueefa1dd72009-08-31 15:55:13 +0800355 mBluetoothService.setRemoteDeviceProperty(address, "Trusted", "false");
Jaikumar Ganesh9488cbd2009-08-03 17:17:37 -0700356 }
Lixin Yueefa1dd72009-08-31 15:55:13 +0800357 } else if (name.equals("Trusted")) {
358 if (DBG)
359 log("set trust state succeded, value is " + propValues[1]);
360 mBluetoothService.setRemoteDeviceProperty(address, name, propValues[1]);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700361 }
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700362 }
363
Jaikumar Ganeshb0eca412009-07-16 18:26:28 -0700364 private String checkPairingRequestAndGetAddress(String objectPath, int nativeData) {
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700365 String address = mBluetoothService.getAddressFromObjectPath(objectPath);
366 if (address == null) {
Jaikumar Ganeshb0eca412009-07-16 18:26:28 -0700367 Log.e(TAG, "Unable to get device address in checkPairingRequestAndGetAddress, " +
368 "returning null");
369 return null;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700370 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800371 address = address.toUpperCase();
372 mPasskeyAgentRequestData.put(address, new Integer(nativeData));
373
Nick Pellyde893f52009-09-08 13:15:33 -0700374 if (mBluetoothService.getBluetoothState() == BluetoothAdapter.STATE_TURNING_OFF) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700375 // shutdown path
Jaikumar Ganeshb0eca412009-07-16 18:26:28 -0700376 mBluetoothService.cancelPairingUserInput(address);
377 return null;
The Android Open Source Project10592532009-03-18 17:39:46 -0700378 }
Jaikumar Ganeshb0eca412009-07-16 18:26:28 -0700379 return address;
380 }
381
382 private void onRequestConfirmation(String objectPath, int passkey, int nativeData) {
383 String address = checkPairingRequestAndGetAddress(objectPath, nativeData);
384 if (address == null) return;
385
386 Intent intent = new Intent(BluetoothIntent.PAIRING_REQUEST_ACTION);
Nick Pellybd022f42009-08-14 18:33:38 -0700387 intent.putExtra(BluetoothIntent.DEVICE, mAdapter.getRemoteDevice(address));
Jaikumar Ganeshb0eca412009-07-16 18:26:28 -0700388 intent.putExtra(BluetoothIntent.PASSKEY, passkey);
389 intent.putExtra(BluetoothIntent.PAIRING_VARIANT,
390 BluetoothDevice.PAIRING_VARIANT_CONFIRMATION);
391 mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
392 return;
393 }
394
395 private void onRequestPasskey(String objectPath, int nativeData) {
396 String address = checkPairingRequestAndGetAddress(objectPath, nativeData);
397 if (address == null) return;
398
399 Intent intent = new Intent(BluetoothIntent.PAIRING_REQUEST_ACTION);
Nick Pellybd022f42009-08-14 18:33:38 -0700400 intent.putExtra(BluetoothIntent.DEVICE, mAdapter.getRemoteDevice(address));
Jaikumar Ganeshb0eca412009-07-16 18:26:28 -0700401 intent.putExtra(BluetoothIntent.PAIRING_VARIANT, BluetoothDevice.PAIRING_VARIANT_PASSKEY);
402 mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
403 return;
404 }
405
406 private void onRequestPinCode(String objectPath, int nativeData) {
407 String address = checkPairingRequestAndGetAddress(objectPath, nativeData);
408 if (address == null) return;
The Android Open Source Project10592532009-03-18 17:39:46 -0700409
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800410 if (mBluetoothService.getBondState().getBondState(address) ==
411 BluetoothDevice.BOND_BONDING) {
412 // we initiated the bonding
413 int btClass = mBluetoothService.getRemoteClass(address);
414
415 // try 0000 once if the device looks dumb
416 switch (BluetoothClass.Device.getDevice(btClass)) {
417 case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
418 case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
419 case BluetoothClass.Device.AUDIO_VIDEO_HEADPHONES:
420 case BluetoothClass.Device.AUDIO_VIDEO_PORTABLE_AUDIO:
421 case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
422 case BluetoothClass.Device.AUDIO_VIDEO_HIFI_AUDIO:
423 if (!mBluetoothService.getBondState().hasAutoPairingFailed(address) &&
424 !mBluetoothService.getBondState().isAutoPairingBlacklisted(address)) {
425 mBluetoothService.getBondState().attempt(address);
426 mBluetoothService.setPin(address, BluetoothDevice.convertPinToBytes("0000"));
427 return;
428 }
429 }
430 }
431 Intent intent = new Intent(BluetoothIntent.PAIRING_REQUEST_ACTION);
Nick Pellybd022f42009-08-14 18:33:38 -0700432 intent.putExtra(BluetoothIntent.DEVICE, mAdapter.getRemoteDevice(address));
Jaikumar Ganeshb0eca412009-07-16 18:26:28 -0700433 intent.putExtra(BluetoothIntent.PAIRING_VARIANT, BluetoothDevice.PAIRING_VARIANT_PIN);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800434 mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700435 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800436 }
437
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700438 private boolean onAgentAuthorize(String objectPath, String deviceUuid) {
439 String address = mBluetoothService.getAddressFromObjectPath(objectPath);
440 if (address == null) {
441 Log.e(TAG, "Unable to get device address in onAuthAgentAuthorize");
442 return false;
443 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800444
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800445 boolean authorized = false;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700446 UUID uuid = UUID.fromString(deviceUuid);
Nick Pellyb23d4452009-08-26 09:33:40 -0700447 // Bluez sends the UUID of the local service being accessed, _not_ the
448 // remote service
Jaikumar Ganeshade40522009-07-30 13:32:25 -0700449 if (mBluetoothService.isEnabled() &&
Nick Pellyb23d4452009-08-26 09:33:40 -0700450 (BluetoothUuid.isAudioSource(uuid) || BluetoothUuid.isAvrcpTarget(uuid)
Jaikumar Ganesh9488cbd2009-08-03 17:17:37 -0700451 || BluetoothUuid.isAdvAudioDist(uuid))) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800452 BluetoothA2dp a2dp = new BluetoothA2dp(mContext);
Nick Pellybd022f42009-08-14 18:33:38 -0700453 BluetoothDevice device = mAdapter.getRemoteDevice(address);
454 authorized = a2dp.getSinkPriority(device) > BluetoothA2dp.PRIORITY_OFF;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800455 if (authorized) {
Jaikumar Ganeshade40522009-07-30 13:32:25 -0700456 Log.i(TAG, "Allowing incoming A2DP / AVRCP connection from " + address);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800457 } else {
Jaikumar Ganeshade40522009-07-30 13:32:25 -0700458 Log.i(TAG, "Rejecting incoming A2DP / AVRCP connection from " + address);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800459 }
460 } else {
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700461 Log.i(TAG, "Rejecting incoming " + deviceUuid + " connection from " + address);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800462 }
Nick Pellyb23d4452009-08-26 09:33:40 -0700463 log("onAgentAuthorize(" + objectPath + ", " + deviceUuid + ") = " + authorized);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800464 return authorized;
465 }
466
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700467 private void onAgentCancel() {
Jaikumar Ganeshb0eca412009-07-16 18:26:28 -0700468 Intent intent = new Intent(BluetoothIntent.PAIRING_CANCEL_ACTION);
469 mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
470 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800471 }
472
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700473 private void onRestartRequired() {
474 if (mBluetoothService.isEnabled()) {
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700475 Log.e(TAG, "*** A serious error occured (did bluetoothd crash?) - " +
476 "restarting Bluetooth ***");
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700477 mHandler.sendEmptyMessage(EVENT_RESTART_BLUETOOTH);
478 }
479 }
480
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800481 private static void log(String msg) {
482 Log.d(TAG, msg);
483 }
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700484
485 private native void initializeNativeDataNative();
486 private native void startEventLoopNative();
487 private native void stopEventLoopNative();
488 private native boolean isEventLoopRunningNative();
489 private native void cleanupNativeDataNative();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800490}