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