blob: d0d4b84997fe314d9eb03b470b164c54c4d2344f [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;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -070023import android.bluetooth.BluetoothUuid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080024import android.content.Context;
25import android.content.Intent;
26import android.os.Handler;
27import android.os.Message;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028import android.util.Log;
29
30import java.util.HashMap;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -070031import java.util.UUID;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032
33/**
34 * TODO: Move this to
35 * java/services/com/android/server/BluetoothEventLoop.java
36 * and make the contructor package private again.
37 *
38 * @hide
39 */
40class BluetoothEventLoop {
41 private static final String TAG = "BluetoothEventLoop";
42 private static final boolean DBG = false;
43
44 private int mNativeData;
45 private Thread mThread;
The Android Open Source Projectb2a3dd82009-03-09 11:52:12 -070046 private boolean mStarted;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047 private boolean mInterrupted;
Nick Pellybd022f42009-08-14 18:33:38 -070048
The Android Open Source Project10592532009-03-18 17:39:46 -070049 private final HashMap<String, Integer> mPasskeyAgentRequestData;
Nick Pellybd022f42009-08-14 18:33:38 -070050 private final BluetoothService mBluetoothService;
51 private final BluetoothAdapter mAdapter;
The Android Open Source Project10592532009-03-18 17:39:46 -070052 private final Context mContext;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053
54 private static final int EVENT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 1;
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -070055 private static final int EVENT_RESTART_BLUETOOTH = 2;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056
57 // The time (in millisecs) to delay the pairing attempt after the first
58 // auto pairing attempt fails. We use an exponential delay with
59 // INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY as the initial value and
60 // MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY as the max value.
61 private static final long INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 3000;
62 private static final long MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 12000;
63
64 private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
65 private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
66
67 private final Handler mHandler = new Handler() {
68 @Override
69 public void handleMessage(Message msg) {
70 switch (msg.what) {
71 case EVENT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY:
72 String address = (String)msg.obj;
73 if (address != null) {
74 mBluetoothService.createBond(address);
75 return;
76 }
77 break;
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;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080081 }
82 }
83 };
84
85 static { classInitNative(); }
86 private static native void classInitNative();
87
Nick Pellybd022f42009-08-14 18:33:38 -070088 /* pacakge */ BluetoothEventLoop(Context context, BluetoothAdapter adapter,
89 BluetoothService bluetoothService) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090 mBluetoothService = bluetoothService;
91 mContext = context;
92 mPasskeyAgentRequestData = new HashMap();
Nick Pellybd022f42009-08-14 18:33:38 -070093 mAdapter = adapter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094 initializeNativeDataNative();
95 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080096
97 protected void finalize() throws Throwable {
98 try {
99 cleanupNativeDataNative();
100 } finally {
101 super.finalize();
102 }
103 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700105 /* package */ HashMap<String, Integer> getPasskeyAgentRequestData() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106 return mPasskeyAgentRequestData;
107 }
108
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700109 /* package */ void start() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700111 if (!isEventLoopRunningNative()) {
112 if (DBG) log("Starting Event Loop thread");
113 startEventLoopNative();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800114 }
115 }
116
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700117 public void stop() {
118 if (isEventLoopRunningNative()) {
119 if (DBG) log("Stopping Event Loop thread");
120 stopEventLoopNative();
121 }
122 }
123
124 public boolean isEventLoopRunning() {
125 return isEventLoopRunningNative();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800126 }
127
Jaikumar Ganesh9488cbd2009-08-03 17:17:37 -0700128 private void addDevice(String address, String[] properties) {
129 mBluetoothService.addRemoteDeviceProperties(address, properties);
130 String rssi = mBluetoothService.getRemoteDeviceProperty(address, "RSSI");
131 String classValue = mBluetoothService.getRemoteDeviceProperty(address, "Class");
132 String name = mBluetoothService.getRemoteDeviceProperty(address, "Name");
133 short rssiValue;
134 // For incoming connections, we don't get the RSSI value. Use a default of MIN_VALUE.
135 // If we accept the pairing, we will automatically show it at the top of the list.
136 if (rssi != null) {
137 rssiValue = (short)Integer.valueOf(rssi).intValue();
138 } else {
139 rssiValue = Short.MIN_VALUE;
140 }
141 if (classValue != null) {
Nick Pelly005b2282009-09-10 10:21:56 -0700142 Intent intent = new Intent(BluetoothDevice.ACTION_FOUND);
143 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
144 intent.putExtra(BluetoothDevice.EXTRA_CLASS,
145 new BluetoothClass(Integer.valueOf(classValue)));
146 intent.putExtra(BluetoothDevice.EXTRA_RSSI, rssiValue);
147 intent.putExtra(BluetoothDevice.EXTRA_NAME, name);
Jaikumar Ganesh9488cbd2009-08-03 17:17:37 -0700148
149 mContext.sendBroadcast(intent, BLUETOOTH_PERM);
150 } else {
151 log ("ClassValue: " + classValue + " for remote device: " + address + " is null");
152 }
153 }
154
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700155 private void onDeviceFound(String address, String[] properties) {
156 if (properties == null) {
157 Log.e(TAG, "ERROR: Remote device properties are null");
158 return;
159 }
Jaikumar Ganesh9488cbd2009-08-03 17:17:37 -0700160 addDevice(address, properties);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800161 }
162
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700163 private void onDeviceDisappeared(String address) {
Nick Pelly005b2282009-09-10 10:21:56 -0700164 Intent intent = new Intent(BluetoothDevice.ACTION_DISAPPEARED);
165 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800166 mContext.sendBroadcast(intent, BLUETOOTH_PERM);
167 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800168
Jaikumar Ganesh5e59ca82009-09-11 12:16:19 -0700169 private void onDeviceDisconnectRequested(String deviceObjectPath) {
170 String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath);
171 if (address == null) {
172 Log.e(TAG, "onDeviceDisconnectRequested: Address of the remote device in null");
173 return;
174 }
175 Intent intent = new Intent(BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED);
176 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
177 mContext.sendBroadcast(intent, BLUETOOTH_PERM);
178 }
179
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700180 private void onCreatePairedDeviceResult(String address, int result) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800181 address = address.toUpperCase();
Nick Pellyb24e11b2009-09-08 17:40:43 -0700182 if (result == BluetoothDevice.BOND_SUCCESS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800183 mBluetoothService.getBondState().setBondState(address, BluetoothDevice.BOND_BONDED);
184 if (mBluetoothService.getBondState().isAutoPairingAttemptsInProgress(address)) {
185 mBluetoothService.getBondState().clearPinAttempts(address);
186 }
187 } else if (result == BluetoothDevice.UNBOND_REASON_AUTH_FAILED &&
188 mBluetoothService.getBondState().getAttempt(address) == 1) {
189 mBluetoothService.getBondState().addAutoPairingFailure(address);
190 pairingAttempt(address, result);
191 } else if (result == BluetoothDevice.UNBOND_REASON_REMOTE_DEVICE_DOWN &&
192 mBluetoothService.getBondState().isAutoPairingAttemptsInProgress(address)) {
193 pairingAttempt(address, result);
194 } else {
195 mBluetoothService.getBondState().setBondState(address,
Nick Pelly005b2282009-09-10 10:21:56 -0700196 BluetoothDevice.BOND_NONE, result);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800197 if (mBluetoothService.getBondState().isAutoPairingAttemptsInProgress(address)) {
198 mBluetoothService.getBondState().clearPinAttempts(address);
199 }
200 }
201 }
202
203 private void pairingAttempt(String address, int result) {
204 // This happens when our initial guess of "0000" as the pass key
205 // fails. Try to create the bond again and display the pin dialog
206 // to the user. Use back-off while posting the delayed
207 // message. The initial value is
208 // INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY and the max value is
209 // MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY. If the max value is
210 // reached, display an error to the user.
211 int attempt = mBluetoothService.getBondState().getAttempt(address);
212 if (attempt * INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY >
213 MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY) {
214 mBluetoothService.getBondState().clearPinAttempts(address);
215 mBluetoothService.getBondState().setBondState(address,
Nick Pelly005b2282009-09-10 10:21:56 -0700216 BluetoothDevice.BOND_NONE, result);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800217 return;
218 }
219
220 Message message = mHandler.obtainMessage(EVENT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY);
221 message.obj = address;
222 boolean postResult = mHandler.sendMessageDelayed(message,
223 attempt * INIT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY);
224 if (!postResult) {
225 mBluetoothService.getBondState().clearPinAttempts(address);
226 mBluetoothService.getBondState().setBondState(address,
Nick Pelly005b2282009-09-10 10:21:56 -0700227 BluetoothDevice.BOND_NONE, result);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800228 return;
229 }
230 mBluetoothService.getBondState().attempt(address);
231 }
232
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700233 private void onDeviceCreated(String deviceObjectPath) {
Jaikumar Ganesh9488cbd2009-08-03 17:17:37 -0700234 String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath);
235 if (!mBluetoothService.isRemoteDeviceInCache(address)) {
236 // Incoming connection, we haven't seen this device, add to cache.
237 String[] properties = mBluetoothService.getRemoteDeviceProperties(address);
238 if (properties != null) {
239 addDevice(address, properties);
240 }
241 }
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700242 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800243 }
244
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700245 private void onDeviceRemoved(String deviceObjectPath) {
246 String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath);
247 if (address != null)
248 mBluetoothService.getBondState().setBondState(address.toUpperCase(),
Nick Pelly005b2282009-09-10 10:21:56 -0700249 BluetoothDevice.BOND_NONE, BluetoothDevice.UNBOND_REASON_REMOVED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800250 }
251
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700252 /*package*/ void onPropertyChanged(String[] propValues) {
Jaikumar Ganesh9519ce72009-09-08 21:37:32 -0700253 if (mBluetoothService.isAdapterPropertiesEmpty()) {
254 // We have got a property change before
255 // we filled up our cache.
256 mBluetoothService.getAllProperties();
257 }
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700258 String name = propValues[0];
259 if (name.equals("Name")) {
Nick Pelly005b2282009-09-10 10:21:56 -0700260 Intent intent = new Intent(BluetoothDevice.ACTION_NAME_CHANGED);
261 intent.putExtra(BluetoothDevice.EXTRA_NAME, propValues[1]);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700262 mContext.sendBroadcast(intent, BLUETOOTH_PERM);
263 mBluetoothService.setProperty(name, propValues[1]);
264 } else if (name.equals("Pairable") || name.equals("Discoverable")) {
265 String pairable = name.equals("Pairable") ? propValues[1] :
266 mBluetoothService.getProperty("Pairable");
267 String discoverable = name.equals("Discoverable") ? propValues[1] :
268 mBluetoothService.getProperty("Discoverable");
269
270 // This shouldn't happen, unless Adapter Properties are null.
271 if (pairable == null || discoverable == null)
272 return;
273
Nick Pellybd022f42009-08-14 18:33:38 -0700274 int mode = BluetoothService.bluezStringToScanMode(
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700275 pairable.equals("true"),
276 discoverable.equals("true"));
277 if (mode >= 0) {
Nick Pellyde893f52009-09-08 13:15:33 -0700278 Intent intent = new Intent(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
279 intent.putExtra(BluetoothAdapter.EXTRA_SCAN_MODE, mode);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700280 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
281 mContext.sendBroadcast(intent, BLUETOOTH_PERM);
282 }
283 mBluetoothService.setProperty(name, propValues[1]);
284 } else if (name.equals("Discovering")) {
285 Intent intent;
286 if (propValues[1].equals("true")) {
287 mBluetoothService.setIsDiscovering(true);
Nick Pelly005b2282009-09-10 10:21:56 -0700288 intent = new Intent(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700289 } else {
290 // Stop the discovery.
291 mBluetoothService.cancelDiscovery();
292 mBluetoothService.setIsDiscovering(false);
Nick Pelly005b2282009-09-10 10:21:56 -0700293 intent = new Intent(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700294 }
295 mContext.sendBroadcast(intent, BLUETOOTH_PERM);
296 mBluetoothService.setProperty(name, propValues[1]);
297 } else if (name.equals("Devices")) {
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700298 String value = null;
299 int len = Integer.valueOf(propValues[1]);
300 if (len > 0) {
Jaikumar Ganeshefa33672009-08-28 13:48:55 -0700301 StringBuilder str = new StringBuilder();
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700302 for (int i = 2; i < propValues.length; i++) {
Jaikumar Ganeshefa33672009-08-28 13:48:55 -0700303 str.append(propValues[i]);
304 str.append(",");
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700305 }
Jaikumar Ganeshefa33672009-08-28 13:48:55 -0700306 value = str.toString();
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700307 }
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700308 mBluetoothService.setProperty(name, value);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700309 } else if (name.equals("Powered")) {
310 // bluetoothd has restarted, re-read all our properties.
311 // Note: bluez only sends this property change when it restarts.
312 if (propValues[1].equals("true"))
313 onRestartRequired();
314 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800315 }
316
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700317 private void onDevicePropertyChanged(String deviceObjectPath, String[] propValues) {
318 String name = propValues[0];
319 String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath);
320 if (address == null) {
321 Log.e(TAG, "onDevicePropertyChanged: Address of the remote device in null");
322 return;
323 }
Nick Pellybd022f42009-08-14 18:33:38 -0700324 BluetoothDevice device = mAdapter.getRemoteDevice(address);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700325 if (name.equals("Name")) {
Nick Pelly005b2282009-09-10 10:21:56 -0700326 Intent intent = new Intent(BluetoothDevice.ACTION_NAME_CHANGED);
327 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
328 intent.putExtra(BluetoothDevice.EXTRA_NAME, propValues[1]);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700329 mContext.sendBroadcast(intent, BLUETOOTH_PERM);
330 mBluetoothService.setRemoteDeviceProperty(address, name, propValues[1]);
331 } else if (name.equals("Class")) {
Nick Pelly005b2282009-09-10 10:21:56 -0700332 Intent intent = new Intent(BluetoothDevice.ACTION_CLASS_CHANGED);
333 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
334 intent.putExtra(BluetoothDevice.EXTRA_CLASS,
335 new BluetoothClass(Integer.valueOf(propValues[1])));
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700336 mContext.sendBroadcast(intent, BLUETOOTH_PERM);
337 mBluetoothService.setRemoteDeviceProperty(address, name, propValues[1]);
338 } else if (name.equals("Connected")) {
339 Intent intent = null;
340 if (propValues[1].equals("true")) {
Nick Pelly005b2282009-09-10 10:21:56 -0700341 intent = new Intent(BluetoothDevice.ACTION_ACL_CONNECTED);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700342 } else {
Nick Pelly005b2282009-09-10 10:21:56 -0700343 intent = new Intent(BluetoothDevice.ACTION_ACL_DISCONNECTED);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700344 }
Nick Pelly005b2282009-09-10 10:21:56 -0700345 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700346 mContext.sendBroadcast(intent, BLUETOOTH_PERM);
347 mBluetoothService.setRemoteDeviceProperty(address, name, propValues[1]);
348 } else if (name.equals("UUIDs")) {
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700349 String uuid = null;
350 int len = Integer.valueOf(propValues[1]);
351 if (len > 0) {
Jaikumar Ganeshefa33672009-08-28 13:48:55 -0700352 StringBuilder str = new StringBuilder();
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700353 for (int i = 2; i < propValues.length; i++) {
Jaikumar Ganeshefa33672009-08-28 13:48:55 -0700354 str.append(propValues[i]);
355 str.append(",");
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700356 }
Jaikumar Ganeshefa33672009-08-28 13:48:55 -0700357 uuid = str.toString();
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700358 }
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700359 mBluetoothService.setRemoteDeviceProperty(address, name, uuid);
Jaikumar Ganesh9488cbd2009-08-03 17:17:37 -0700360 } else if (name.equals("Paired")) {
361 if (propValues[1].equals("true")) {
362 mBluetoothService.getBondState().setBondState(address, BluetoothDevice.BOND_BONDED);
363 } else {
364 mBluetoothService.getBondState().setBondState(address,
Nick Pelly005b2282009-09-10 10:21:56 -0700365 BluetoothDevice.BOND_NONE);
Lixin Yueefa1dd72009-08-31 15:55:13 +0800366 mBluetoothService.setRemoteDeviceProperty(address, "Trusted", "false");
Jaikumar Ganesh9488cbd2009-08-03 17:17:37 -0700367 }
Lixin Yueefa1dd72009-08-31 15:55:13 +0800368 } else if (name.equals("Trusted")) {
369 if (DBG)
370 log("set trust state succeded, value is " + propValues[1]);
371 mBluetoothService.setRemoteDeviceProperty(address, name, propValues[1]);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700372 }
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700373 }
374
Jaikumar Ganeshb0eca412009-07-16 18:26:28 -0700375 private String checkPairingRequestAndGetAddress(String objectPath, int nativeData) {
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700376 String address = mBluetoothService.getAddressFromObjectPath(objectPath);
377 if (address == null) {
Jaikumar Ganeshb0eca412009-07-16 18:26:28 -0700378 Log.e(TAG, "Unable to get device address in checkPairingRequestAndGetAddress, " +
379 "returning null");
380 return null;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700381 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800382 address = address.toUpperCase();
383 mPasskeyAgentRequestData.put(address, new Integer(nativeData));
384
Nick Pellyde893f52009-09-08 13:15:33 -0700385 if (mBluetoothService.getBluetoothState() == BluetoothAdapter.STATE_TURNING_OFF) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700386 // shutdown path
Jaikumar Ganeshb0eca412009-07-16 18:26:28 -0700387 mBluetoothService.cancelPairingUserInput(address);
388 return null;
The Android Open Source Project10592532009-03-18 17:39:46 -0700389 }
Jaikumar Ganeshb0eca412009-07-16 18:26:28 -0700390 return address;
391 }
392
393 private void onRequestConfirmation(String objectPath, int passkey, int nativeData) {
394 String address = checkPairingRequestAndGetAddress(objectPath, nativeData);
395 if (address == null) return;
396
Nick Pelly005b2282009-09-10 10:21:56 -0700397 Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
398 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
399 intent.putExtra(BluetoothDevice.EXTRA_PASSKEY, passkey);
400 intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
Jaikumar Ganeshb0eca412009-07-16 18:26:28 -0700401 BluetoothDevice.PAIRING_VARIANT_CONFIRMATION);
402 mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
403 return;
404 }
405
406 private void onRequestPasskey(String objectPath, int nativeData) {
407 String address = checkPairingRequestAndGetAddress(objectPath, nativeData);
408 if (address == null) return;
409
Nick Pelly005b2282009-09-10 10:21:56 -0700410 Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
411 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
412 intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
413 BluetoothDevice.PAIRING_VARIANT_PASSKEY);
Jaikumar Ganeshb0eca412009-07-16 18:26:28 -0700414 mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
415 return;
416 }
417
418 private void onRequestPinCode(String objectPath, int nativeData) {
419 String address = checkPairingRequestAndGetAddress(objectPath, nativeData);
420 if (address == null) return;
The Android Open Source Project10592532009-03-18 17:39:46 -0700421
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800422 if (mBluetoothService.getBondState().getBondState(address) ==
423 BluetoothDevice.BOND_BONDING) {
424 // we initiated the bonding
Nick Pelly005b2282009-09-10 10:21:56 -0700425 BluetoothClass btClass = new BluetoothClass(mBluetoothService.getRemoteClass(address));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800426
427 // try 0000 once if the device looks dumb
Nick Pelly005b2282009-09-10 10:21:56 -0700428 switch (btClass.getDeviceClass()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800429 case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
430 case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
431 case BluetoothClass.Device.AUDIO_VIDEO_HEADPHONES:
432 case BluetoothClass.Device.AUDIO_VIDEO_PORTABLE_AUDIO:
433 case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
434 case BluetoothClass.Device.AUDIO_VIDEO_HIFI_AUDIO:
435 if (!mBluetoothService.getBondState().hasAutoPairingFailed(address) &&
436 !mBluetoothService.getBondState().isAutoPairingBlacklisted(address)) {
437 mBluetoothService.getBondState().attempt(address);
438 mBluetoothService.setPin(address, BluetoothDevice.convertPinToBytes("0000"));
439 return;
440 }
441 }
442 }
Nick Pelly005b2282009-09-10 10:21:56 -0700443 Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
444 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
445 intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, BluetoothDevice.PAIRING_VARIANT_PIN);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800446 mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700447 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800448 }
449
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700450 private boolean onAgentAuthorize(String objectPath, String deviceUuid) {
451 String address = mBluetoothService.getAddressFromObjectPath(objectPath);
452 if (address == null) {
453 Log.e(TAG, "Unable to get device address in onAuthAgentAuthorize");
454 return false;
455 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800456
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800457 boolean authorized = false;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700458 UUID uuid = UUID.fromString(deviceUuid);
Nick Pellyb23d4452009-08-26 09:33:40 -0700459 // Bluez sends the UUID of the local service being accessed, _not_ the
460 // remote service
Jaikumar Ganeshade40522009-07-30 13:32:25 -0700461 if (mBluetoothService.isEnabled() &&
Nick Pellyb23d4452009-08-26 09:33:40 -0700462 (BluetoothUuid.isAudioSource(uuid) || BluetoothUuid.isAvrcpTarget(uuid)
Jaikumar Ganesh9488cbd2009-08-03 17:17:37 -0700463 || BluetoothUuid.isAdvAudioDist(uuid))) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800464 BluetoothA2dp a2dp = new BluetoothA2dp(mContext);
Nick Pellybd022f42009-08-14 18:33:38 -0700465 BluetoothDevice device = mAdapter.getRemoteDevice(address);
466 authorized = a2dp.getSinkPriority(device) > BluetoothA2dp.PRIORITY_OFF;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800467 if (authorized) {
Jaikumar Ganeshade40522009-07-30 13:32:25 -0700468 Log.i(TAG, "Allowing incoming A2DP / AVRCP connection from " + address);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800469 } else {
Jaikumar Ganeshade40522009-07-30 13:32:25 -0700470 Log.i(TAG, "Rejecting incoming A2DP / AVRCP connection from " + address);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800471 }
472 } else {
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700473 Log.i(TAG, "Rejecting incoming " + deviceUuid + " connection from " + address);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800474 }
Nick Pellyb23d4452009-08-26 09:33:40 -0700475 log("onAgentAuthorize(" + objectPath + ", " + deviceUuid + ") = " + authorized);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800476 return authorized;
477 }
478
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700479 private void onAgentCancel() {
Nick Pelly005b2282009-09-10 10:21:56 -0700480 Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_CANCEL);
Jaikumar Ganeshb0eca412009-07-16 18:26:28 -0700481 mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
482 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800483 }
484
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700485 private void onRestartRequired() {
486 if (mBluetoothService.isEnabled()) {
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700487 Log.e(TAG, "*** A serious error occured (did bluetoothd crash?) - " +
488 "restarting Bluetooth ***");
The Android Open Source Projectc39a6e02009-03-11 12:11:56 -0700489 mHandler.sendEmptyMessage(EVENT_RESTART_BLUETOOTH);
490 }
491 }
492
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800493 private static void log(String msg) {
494 Log.d(TAG, msg);
495 }
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700496
497 private native void initializeNativeDataNative();
498 private native void startEventLoopNative();
499 private native void stopEventLoopNative();
500 private native boolean isEventLoopRunningNative();
501 private native void cleanupNativeDataNative();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800502}