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