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