PanService.java revision cdd2da9489cdfcf35ffdc622eba6f2155f6d376e
1/* 2 * Copyright (C) 2012 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 com.android.bluetooth.pan; 18 19import android.app.Service; 20import android.bluetooth.BluetoothDevice; 21import android.bluetooth.BluetoothPan; 22import android.bluetooth.BluetoothProfile; 23import android.bluetooth.BluetoothTetheringDataTracker; 24import android.bluetooth.IBluetooth; 25import android.bluetooth.IBluetoothPan; 26import android.content.Context; 27import android.content.Intent; 28import android.content.pm.PackageManager; 29import android.content.res.Resources.NotFoundException; 30import android.net.ConnectivityManager; 31import android.net.InterfaceConfiguration; 32import android.net.LinkAddress; 33import android.net.LinkProperties; 34import android.net.NetworkStateTracker; 35import android.net.NetworkUtils; 36import android.os.Handler; 37import android.os.IBinder; 38import android.os.INetworkManagementService; 39import android.os.Message; 40import android.os.Messenger; 41import android.os.RemoteException; 42import android.os.ServiceManager; 43import android.provider.Settings; 44import android.util.Log; 45import com.android.bluetooth.btservice.ProfileService; 46import com.android.bluetooth.Utils; 47import com.android.internal.util.AsyncChannel; 48import java.net.InetAddress; 49import java.util.ArrayList; 50import java.util.Collections; 51import java.util.HashMap; 52import java.util.List; 53import java.util.Map; 54import android.content.SharedPreferences; 55import android.content.SharedPreferences.Editor; 56 57/** 58 * Provides Bluetooth Pan Device profile, as a service in 59 * the Bluetooth application. 60 * @hide 61 */ 62public class PanService extends ProfileService { 63 private static final String TAG = "PanService"; 64 private static final boolean DBG = false; 65 66 private static final String BLUETOOTH_IFACE_ADDR_START= "192.168.44.1"; 67 private static final int BLUETOOTH_MAX_PAN_CONNECTIONS = 5; 68 private static final int BLUETOOTH_PREFIX_LENGTH = 24; 69 70 private HashMap<BluetoothDevice, BluetoothPanDevice> mPanDevices; 71 private ArrayList<String> mBluetoothIfaceAddresses; 72 private int mMaxPanDevices; 73 private String mPanIfName; 74 private boolean mNativeAvailable; 75 76 private static final int MESSAGE_CONNECT = 1; 77 private static final int MESSAGE_DISCONNECT = 2; 78 private static final int MESSAGE_CONNECT_STATE_CHANGED = 11; 79 private boolean mTetherOn = false; 80 private static final String PAN_PREFERENCE_FILE = "PANMGR"; 81 private static final String PAN_TETHER_SETTING = "TETHERSTATE"; 82 83 AsyncChannel mTetherAc; 84 85 86 static { 87 classInitNative(); 88 } 89 90 protected String getName() { 91 return TAG; 92 } 93 94 public IProfileServiceBinder initBinder() { 95 return new BluetoothPanBinder(this); 96 } 97 98 protected boolean start() { 99 mPanDevices = new HashMap<BluetoothDevice, BluetoothPanDevice>(); 100 mBluetoothIfaceAddresses = new ArrayList<String>(); 101 try { 102 mMaxPanDevices = getResources().getInteger( 103 com.android.internal.R.integer.config_max_pan_devices); 104 } catch (NotFoundException e) { 105 mMaxPanDevices = BLUETOOTH_MAX_PAN_CONNECTIONS; 106 } 107 initializeNative(); 108 mNativeAvailable=true; 109 110 ConnectivityManager cm = (ConnectivityManager) getSystemService( 111 Context.CONNECTIVITY_SERVICE); 112 cm.supplyMessenger(ConnectivityManager.TYPE_BLUETOOTH, new Messenger(mHandler)); 113 114 // Set mTetherOn based on the last saved tethering preference while starting the Pan service 115 SharedPreferences tetherSetting = getSharedPreferences(PAN_PREFERENCE_FILE, 0); 116 mTetherOn = tetherSetting.getBoolean(PAN_TETHER_SETTING, false); 117 118 return true; 119 } 120 121 protected boolean stop() { 122 mHandler.removeCallbacksAndMessages(null); 123 if (mTetherAc != null) { 124 mTetherAc.disconnect(); 125 mTetherAc = null; 126 } 127 return true; 128 } 129 130 protected boolean cleanup() { 131 if (mNativeAvailable) { 132 cleanupNative(); 133 mNativeAvailable=false; 134 } 135 if(mPanDevices != null) { 136 List<BluetoothDevice> DevList = getConnectedDevices(); 137 for(BluetoothDevice dev : DevList) { 138 handlePanDeviceStateChange(dev, mPanIfName, BluetoothProfile.STATE_DISCONNECTED, 139 BluetoothPan.LOCAL_PANU_ROLE, BluetoothPan.REMOTE_NAP_ROLE); 140 } 141 mPanDevices.clear(); 142 } 143 if(mBluetoothIfaceAddresses != null) { 144 mBluetoothIfaceAddresses.clear(); 145 } 146 return true; 147 } 148 149 private final Handler mHandler = new Handler() { 150 @Override 151 public void handleMessage(Message msg) { 152 switch (msg.what) { 153 case MESSAGE_CONNECT: 154 { 155 BluetoothDevice device = (BluetoothDevice) msg.obj; 156 if (!connectPanNative(Utils.getByteAddress(device), 157 BluetoothPan.LOCAL_PANU_ROLE, BluetoothPan.REMOTE_NAP_ROLE)) { 158 handlePanDeviceStateChange(device, null, BluetoothProfile.STATE_CONNECTING, 159 BluetoothPan.LOCAL_PANU_ROLE, BluetoothPan.REMOTE_NAP_ROLE); 160 handlePanDeviceStateChange(device, null, 161 BluetoothProfile.STATE_DISCONNECTED, BluetoothPan.LOCAL_PANU_ROLE, 162 BluetoothPan.REMOTE_NAP_ROLE); 163 break; 164 } 165 } 166 break; 167 case MESSAGE_DISCONNECT: 168 { 169 BluetoothDevice device = (BluetoothDevice) msg.obj; 170 if (!disconnectPanNative(Utils.getByteAddress(device)) ) { 171 handlePanDeviceStateChange(device, mPanIfName, 172 BluetoothProfile.STATE_DISCONNECTING, BluetoothPan.LOCAL_PANU_ROLE, 173 BluetoothPan.REMOTE_NAP_ROLE); 174 handlePanDeviceStateChange(device, mPanIfName, 175 BluetoothProfile.STATE_DISCONNECTED, BluetoothPan.LOCAL_PANU_ROLE, 176 BluetoothPan.REMOTE_NAP_ROLE); 177 break; 178 } 179 } 180 break; 181 case MESSAGE_CONNECT_STATE_CHANGED: 182 { 183 ConnectState cs = (ConnectState)msg.obj; 184 BluetoothDevice device = getDevice(cs.addr); 185 // TBD get iface from the msg 186 if (DBG) { 187 log("MESSAGE_CONNECT_STATE_CHANGED: " + device + " state: " + cs.state); 188 } 189 handlePanDeviceStateChange(device, mPanIfName /* iface */, 190 convertHalState(cs.state), cs.local_role, cs.remote_role); 191 } 192 break; 193 case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: 194 { 195 if (mTetherAc != null) { 196 mTetherAc.replyToMessage(msg, 197 AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED, 198 AsyncChannel.STATUS_FULL_CONNECTION_REFUSED_ALREADY_CONNECTED); 199 } else { 200 mTetherAc = new AsyncChannel(); 201 mTetherAc.connected(null, this, msg.replyTo); 202 mTetherAc.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED, 203 AsyncChannel.STATUS_SUCCESSFUL); 204 } 205 } 206 break; 207 case AsyncChannel.CMD_CHANNEL_DISCONNECT: 208 { 209 if (mTetherAc != null) { 210 mTetherAc.disconnect(); 211 mTetherAc = null; 212 } 213 } 214 break; 215 } 216 } 217 }; 218 219 /** 220 * Handlers for incoming service calls 221 */ 222 private static class BluetoothPanBinder extends IBluetoothPan.Stub 223 implements IProfileServiceBinder { 224 private PanService mService; 225 public BluetoothPanBinder(PanService svc) { 226 mService = svc; 227 } 228 public boolean cleanup() { 229 mService = null; 230 return true; 231 } 232 private PanService getService() { 233 if (!Utils.checkCaller()) { 234 Log.w(TAG,"Pan call not allowed for non-active user"); 235 return null; 236 } 237 238 if (mService != null && mService.isAvailable()) { 239 return mService; 240 } 241 return null; 242 } 243 public boolean connect(BluetoothDevice device) { 244 PanService service = getService(); 245 if (service == null) return false; 246 return service.connect(device); 247 } 248 public boolean disconnect(BluetoothDevice device) { 249 PanService service = getService(); 250 if (service == null) return false; 251 return service.disconnect(device); 252 } 253 public int getConnectionState(BluetoothDevice device) { 254 PanService service = getService(); 255 if (service == null) return BluetoothPan.STATE_DISCONNECTED; 256 return service.getConnectionState(device); 257 } 258 private boolean isPanNapOn() { 259 PanService service = getService(); 260 if (service == null) return false; 261 return service.isPanNapOn(); 262 } 263 private boolean isPanUOn() { 264 if(DBG) Log.d(TAG, "isTetheringOn call getPanLocalRoleNative"); 265 PanService service = getService(); 266 return service.isPanUOn(); 267 } 268 public boolean isTetheringOn() { 269 PanService service = getService(); 270 if (service == null) return false; 271 return service.isTetheringOn(); 272 } 273 public void setBluetoothTethering(boolean value) { 274 PanService service = getService(); 275 if (service == null) return; 276 Log.d(TAG, "setBluetoothTethering: " + value +", mTetherOn: " + service.mTetherOn); 277 service.setBluetoothTethering(value); 278 } 279 280 public List<BluetoothDevice> getConnectedDevices() { 281 PanService service = getService(); 282 if (service == null) return new ArrayList<BluetoothDevice>(0); 283 return service.getConnectedDevices(); 284 } 285 286 public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 287 PanService service = getService(); 288 if (service == null) return new ArrayList<BluetoothDevice>(0); 289 return service.getDevicesMatchingConnectionStates(states); 290 } 291 }; 292 293 boolean connect(BluetoothDevice device) { 294 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 295 if (getConnectionState(device) != BluetoothProfile.STATE_DISCONNECTED) { 296 Log.e(TAG, "Pan Device not disconnected: " + device); 297 return false; 298 } 299 Message msg = mHandler.obtainMessage(MESSAGE_CONNECT,device); 300 mHandler.sendMessage(msg); 301 return true; 302 } 303 304 boolean disconnect(BluetoothDevice device) { 305 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 306 Message msg = mHandler.obtainMessage(MESSAGE_DISCONNECT,device); 307 mHandler.sendMessage(msg); 308 return true; 309 } 310 311 int getConnectionState(BluetoothDevice device) { 312 BluetoothPanDevice panDevice = mPanDevices.get(device); 313 if (panDevice == null) { 314 return BluetoothPan.STATE_DISCONNECTED; 315 } 316 return panDevice.mState; 317 } 318 319 boolean isPanNapOn() { 320 if(DBG) Log.d(TAG, "isTetheringOn call getPanLocalRoleNative"); 321 return (getPanLocalRoleNative() & BluetoothPan.LOCAL_NAP_ROLE) != 0; 322 } 323 boolean isPanUOn() { 324 if(DBG) Log.d(TAG, "isTetheringOn call getPanLocalRoleNative"); 325 return (getPanLocalRoleNative() & BluetoothPan.LOCAL_PANU_ROLE) != 0; 326 } 327 boolean isTetheringOn() { 328 return mTetherOn; 329 } 330 331 void setBluetoothTethering(boolean value) { 332 if(DBG) Log.d(TAG, "setBluetoothTethering: " + value +", mTetherOn: " + mTetherOn); 333 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); 334 if(mTetherOn != value) { 335 336 SharedPreferences tetherSetting = getSharedPreferences(PAN_PREFERENCE_FILE, 0); 337 SharedPreferences.Editor editor = tetherSetting.edit(); 338 339 editor.putBoolean(PAN_TETHER_SETTING, value); 340 341 // Commit the edit! 342 editor.commit(); 343 //drop any existing panu or pan-nap connection when changing the tethering state 344 mTetherOn = value; 345 List<BluetoothDevice> DevList = getConnectedDevices(); 346 for(BluetoothDevice dev : DevList) 347 disconnect(dev); 348 } 349 } 350 351 List<BluetoothDevice> getConnectedDevices() { 352 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 353 List<BluetoothDevice> devices = getDevicesMatchingConnectionStates( 354 new int[] {BluetoothProfile.STATE_CONNECTED}); 355 return devices; 356 } 357 358 List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 359 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 360 List<BluetoothDevice> panDevices = new ArrayList<BluetoothDevice>(); 361 362 for (BluetoothDevice device: mPanDevices.keySet()) { 363 int panDeviceState = getConnectionState(device); 364 for (int state : states) { 365 if (state == panDeviceState) { 366 panDevices.add(device); 367 break; 368 } 369 } 370 } 371 return panDevices; 372 } 373 374 static protected class ConnectState { 375 public ConnectState(byte[] address, int state, int error, int local_role, int remote_role) { 376 this.addr = address; 377 this.state = state; 378 this.error = error; 379 this.local_role = local_role; 380 this.remote_role = remote_role; 381 } 382 byte[] addr; 383 int state; 384 int error; 385 int local_role; 386 int remote_role; 387 }; 388 private void onConnectStateChanged(byte[] address, int state, int error, int local_role, 389 int remote_role) { 390 if (DBG) { 391 log("onConnectStateChanged: " + state + ", local role:" + local_role + 392 ", remote_role: " + remote_role); 393 } 394 Message msg = mHandler.obtainMessage(MESSAGE_CONNECT_STATE_CHANGED); 395 msg.obj = new ConnectState(address, state, error, local_role, remote_role); 396 mHandler.sendMessage(msg); 397 } 398 private void onControlStateChanged(int local_role, int state, int error, String ifname) { 399 if (DBG) 400 log("onControlStateChanged: " + state + ", error: " + error + ", ifname: " + ifname); 401 if(error == 0) 402 mPanIfName = ifname; 403 } 404 405 private static int convertHalState(int halState) { 406 switch (halState) { 407 case CONN_STATE_CONNECTED: 408 return BluetoothProfile.STATE_CONNECTED; 409 case CONN_STATE_CONNECTING: 410 return BluetoothProfile.STATE_CONNECTING; 411 case CONN_STATE_DISCONNECTED: 412 return BluetoothProfile.STATE_DISCONNECTED; 413 case CONN_STATE_DISCONNECTING: 414 return BluetoothProfile.STATE_DISCONNECTING; 415 default: 416 Log.e(TAG, "bad pan connection state: " + halState); 417 return BluetoothProfile.STATE_DISCONNECTED; 418 } 419 } 420 421 void handlePanDeviceStateChange(BluetoothDevice device, 422 String iface, int state, int local_role, int remote_role) { 423 if(DBG) { 424 Log.d(TAG, "handlePanDeviceStateChange: device: " + device + ", iface: " + iface + 425 ", state: " + state + ", local_role:" + local_role + ", remote_role:" + 426 remote_role); 427 } 428 int prevState; 429 String ifaceAddr = null; 430 BluetoothPanDevice panDevice = mPanDevices.get(device); 431 if (panDevice == null) { 432 prevState = BluetoothProfile.STATE_DISCONNECTED; 433 } else { 434 prevState = panDevice.mState; 435 ifaceAddr = panDevice.mIfaceAddr; 436 } 437 438 // Avoid race condition that gets this class stuck in STATE_DISCONNECTING. While we 439 // are in STATE_CONNECTING, if a BluetoothPan#disconnect call comes in, the original 440 // connect call will put us in STATE_DISCONNECTED. Then, the disconnect completes and 441 // changes the state to STATE_DISCONNECTING. All future calls to BluetoothPan#connect 442 // will fail until the caller explicitly calls BluetoothPan#disconnect. 443 if (prevState == BluetoothProfile.STATE_DISCONNECTED && state == BluetoothProfile.STATE_DISCONNECTING) { 444 Log.d(TAG, "Ignoring state change from " + prevState + " to " + state); 445 return; 446 } 447 448 Log.d(TAG, "handlePanDeviceStateChange preState: " + prevState + " state: " + state); 449 if (prevState == state) return; 450 if (remote_role == BluetoothPan.LOCAL_PANU_ROLE) { 451 if (state == BluetoothProfile.STATE_CONNECTED) { 452 if((!mTetherOn)||(local_role == BluetoothPan.LOCAL_PANU_ROLE)){ 453 Log.d(TAG,"handlePanDeviceStateChange BT tethering is off/Local role is PANU "+ 454 "drop the connection"); 455 disconnectPanNative(Utils.getByteAddress(device)); 456 return; 457 } 458 Log.d(TAG, "handlePanDeviceStateChange LOCAL_NAP_ROLE:REMOTE_PANU_ROLE"); 459 ifaceAddr = enableTethering(iface); 460 if (ifaceAddr == null) Log.e(TAG, "Error seting up tether interface"); 461 462 } else if (state == BluetoothProfile.STATE_DISCONNECTED) { 463 if (ifaceAddr != null) { 464 mBluetoothIfaceAddresses.remove(ifaceAddr); 465 ifaceAddr = null; 466 } 467 } 468 } else if (mTetherAc != null) { 469 // PANU Role = reverse Tether 470 Log.d(TAG, "handlePanDeviceStateChange LOCAL_PANU_ROLE:REMOTE_NAP_ROLE state = " + 471 state + ", prevState = " + prevState); 472 if (state == BluetoothProfile.STATE_CONNECTED) { 473 LinkProperties lp = new LinkProperties(); 474 lp.setInterfaceName(iface); 475 mTetherAc.sendMessage(NetworkStateTracker.EVENT_NETWORK_CONNECTED, lp); 476 } else if (state == BluetoothProfile.STATE_DISCONNECTED && 477 (prevState == BluetoothProfile.STATE_CONNECTED || 478 prevState == BluetoothProfile.STATE_DISCONNECTING)) { 479 LinkProperties lp = new LinkProperties(); 480 lp.setInterfaceName(iface); 481 mTetherAc.sendMessage(NetworkStateTracker.EVENT_NETWORK_DISCONNECTED, lp); 482 } 483 } 484 485 if (panDevice == null) { 486 panDevice = new BluetoothPanDevice(state, ifaceAddr, iface, local_role); 487 mPanDevices.put(device, panDevice); 488 } else { 489 panDevice.mState = state; 490 panDevice.mIfaceAddr = ifaceAddr; 491 panDevice.mLocalRole = local_role; 492 panDevice.mIface = iface; 493 } 494 495 /* Notifying the connection state change of the profile before sending the intent for 496 connection state change, as it was causing a race condition, with the UI not being 497 updated with the correct connection state. */ 498 Log.d(TAG, "Pan Device state : device: " + device + " State:" + 499 prevState + "->" + state); 500 notifyProfileConnectionStateChanged(device, BluetoothProfile.PAN, state, prevState); 501 Intent intent = new Intent(BluetoothPan.ACTION_CONNECTION_STATE_CHANGED); 502 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 503 intent.putExtra(BluetoothPan.EXTRA_PREVIOUS_STATE, prevState); 504 intent.putExtra(BluetoothPan.EXTRA_STATE, state); 505 intent.putExtra(BluetoothPan.EXTRA_LOCAL_ROLE, local_role); 506 sendBroadcast(intent, BLUETOOTH_PERM); 507 } 508 509 // configured when we start tethering 510 private String enableTethering(String iface) { 511 if (DBG) Log.d(TAG, "updateTetherState:" + iface); 512 513 IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); 514 INetworkManagementService service = INetworkManagementService.Stub.asInterface(b); 515 ConnectivityManager cm = 516 (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); 517 String[] bluetoothRegexs = cm.getTetherableBluetoothRegexs(); 518 519 // bring toggle the interfaces 520 String[] currentIfaces = new String[0]; 521 try { 522 currentIfaces = service.listInterfaces(); 523 } catch (Exception e) { 524 Log.e(TAG, "Error listing Interfaces :" + e); 525 return null; 526 } 527 528 boolean found = false; 529 for (String currIface: currentIfaces) { 530 if (currIface.equals(iface)) { 531 found = true; 532 break; 533 } 534 } 535 536 if (!found) return null; 537 538 String address = createNewTetheringAddressLocked(); 539 if (address == null) return null; 540 541 InterfaceConfiguration ifcg = null; 542 try { 543 ifcg = service.getInterfaceConfig(iface); 544 if (ifcg != null) { 545 InetAddress addr = null; 546 LinkAddress linkAddr = ifcg.getLinkAddress(); 547 if (linkAddr == null || (addr = linkAddr.getAddress()) == null || 548 addr.equals(NetworkUtils.numericToInetAddress("0.0.0.0")) || 549 addr.equals(NetworkUtils.numericToInetAddress("::0"))) { 550 addr = NetworkUtils.numericToInetAddress(address); 551 } 552 ifcg.setInterfaceUp(); 553 ifcg.setLinkAddress(new LinkAddress(addr, BLUETOOTH_PREFIX_LENGTH)); 554 ifcg.clearFlag("running"); 555 // TODO(BT) ifcg.interfaceFlags = ifcg.interfaceFlags.replace(" "," "); 556 service.setInterfaceConfig(iface, ifcg); 557 if (cm.tether(iface) != ConnectivityManager.TETHER_ERROR_NO_ERROR) { 558 Log.e(TAG, "Error tethering "+iface); 559 } 560 } 561 } catch (Exception e) { 562 Log.e(TAG, "Error configuring interface " + iface + ", :" + e); 563 return null; 564 } 565 return address; 566 } 567 568 private String createNewTetheringAddressLocked() { 569 if (getConnectedPanDevices().size() == mMaxPanDevices) { 570 if (DBG) Log.d(TAG, "Max PAN device connections reached"); 571 return null; 572 } 573 String address = BLUETOOTH_IFACE_ADDR_START; 574 while (true) { 575 if (mBluetoothIfaceAddresses.contains(address)) { 576 String[] addr = address.split("\\."); 577 Integer newIp = Integer.parseInt(addr[2]) + 1; 578 address = address.replace(addr[2], newIp.toString()); 579 } else { 580 break; 581 } 582 } 583 mBluetoothIfaceAddresses.add(address); 584 return address; 585 } 586 587 private List<BluetoothDevice> getConnectedPanDevices() { 588 List<BluetoothDevice> devices = new ArrayList<BluetoothDevice>(); 589 590 for (BluetoothDevice device: mPanDevices.keySet()) { 591 if (getPanDeviceConnectionState(device) == BluetoothProfile.STATE_CONNECTED) { 592 devices.add(device); 593 } 594 } 595 return devices; 596 } 597 598 private int getPanDeviceConnectionState(BluetoothDevice device) { 599 BluetoothPanDevice panDevice = mPanDevices.get(device); 600 if (panDevice == null) { 601 return BluetoothProfile.STATE_DISCONNECTED; 602 } 603 return panDevice.mState; 604 } 605 606 private class BluetoothPanDevice { 607 private int mState; 608 private String mIfaceAddr; 609 private String mIface; 610 private int mLocalRole; // Which local role is this PAN device bound to 611 612 BluetoothPanDevice(int state, String ifaceAddr, String iface, int localRole) { 613 mState = state; 614 mIfaceAddr = ifaceAddr; 615 mIface = iface; 616 mLocalRole = localRole; 617 } 618 } 619 620 // Constants matching Hal header file bt_hh.h 621 // bthh_connection_state_t 622 private final static int CONN_STATE_CONNECTED = 0; 623 private final static int CONN_STATE_CONNECTING = 1; 624 private final static int CONN_STATE_DISCONNECTED = 2; 625 private final static int CONN_STATE_DISCONNECTING = 3; 626 627 private native static void classInitNative(); 628 private native void initializeNative(); 629 private native void cleanupNative(); 630 private native boolean connectPanNative(byte[] btAddress, int local_role, int remote_role); 631 private native boolean disconnectPanNative(byte[] btAddress); 632 private native boolean enablePanNative(int local_role); 633 private native int getPanLocalRoleNative(); 634 635} 636