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 return service.isPanUOn(); 230 } isTetheringOn()231 public boolean isTetheringOn() { 232 // TODO(BT) have a variable marking the on/off state 233 PanService service = getService(); 234 if (service == null) return false; 235 return service.isTetheringOn(); 236 } setBluetoothTethering(boolean value)237 public void setBluetoothTethering(boolean value) { 238 PanService service = getService(); 239 if (service == null) return; 240 Log.d(TAG, "setBluetoothTethering: " + value +", mTetherOn: " + service.mTetherOn); 241 service.setBluetoothTethering(value); 242 } 243 getConnectedDevices()244 public List<BluetoothDevice> getConnectedDevices() { 245 PanService service = getService(); 246 if (service == null) return new ArrayList<BluetoothDevice>(0); 247 return service.getConnectedDevices(); 248 } 249 getDevicesMatchingConnectionStates(int[] states)250 public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 251 PanService service = getService(); 252 if (service == null) return new ArrayList<BluetoothDevice>(0); 253 return service.getDevicesMatchingConnectionStates(states); 254 } 255 }; 256 connect(BluetoothDevice device)257 boolean connect(BluetoothDevice device) { 258 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 259 if (getConnectionState(device) != BluetoothProfile.STATE_DISCONNECTED) { 260 Log.e(TAG, "Pan Device not disconnected: " + device); 261 return false; 262 } 263 Message msg = mHandler.obtainMessage(MESSAGE_CONNECT,device); 264 mHandler.sendMessage(msg); 265 return true; 266 } 267 disconnect(BluetoothDevice device)268 boolean disconnect(BluetoothDevice device) { 269 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 270 Message msg = mHandler.obtainMessage(MESSAGE_DISCONNECT,device); 271 mHandler.sendMessage(msg); 272 return true; 273 } 274 getConnectionState(BluetoothDevice device)275 int getConnectionState(BluetoothDevice device) { 276 BluetoothPanDevice panDevice = mPanDevices.get(device); 277 if (panDevice == null) { 278 return BluetoothPan.STATE_DISCONNECTED; 279 } 280 return panDevice.mState; 281 } 282 isPanNapOn()283 boolean isPanNapOn() { 284 if(DBG) Log.d(TAG, "isTetheringOn call getPanLocalRoleNative"); 285 return (getPanLocalRoleNative() & BluetoothPan.LOCAL_NAP_ROLE) != 0; 286 } isPanUOn()287 boolean isPanUOn() { 288 if(DBG) Log.d(TAG, "isTetheringOn call getPanLocalRoleNative"); 289 return (getPanLocalRoleNative() & BluetoothPan.LOCAL_PANU_ROLE) != 0; 290 } isTetheringOn()291 boolean isTetheringOn() { 292 // TODO(BT) have a variable marking the on/off state 293 return mTetherOn; 294 } 295 setBluetoothTethering(boolean value)296 void setBluetoothTethering(boolean value) { 297 if(DBG) Log.d(TAG, "setBluetoothTethering: " + value +", mTetherOn: " + mTetherOn); 298 ConnectivityManager.enforceTetherChangePermission(getBaseContext()); 299 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); 300 UserManager um = (UserManager) getSystemService(Context.USER_SERVICE); 301 if (um.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING)) { 302 throw new SecurityException("DISALLOW_CONFIG_TETHERING is enabled for this user."); 303 } 304 if(mTetherOn != value) { 305 //drop any existing panu or pan-nap connection when changing the tethering state 306 mTetherOn = value; 307 List<BluetoothDevice> DevList = getConnectedDevices(); 308 for(BluetoothDevice dev : DevList) 309 disconnect(dev); 310 } 311 } 312 getConnectedDevices()313 List<BluetoothDevice> getConnectedDevices() { 314 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 315 List<BluetoothDevice> devices = getDevicesMatchingConnectionStates( 316 new int[] {BluetoothProfile.STATE_CONNECTED}); 317 return devices; 318 } 319 getDevicesMatchingConnectionStates(int[] states)320 List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 321 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 322 List<BluetoothDevice> panDevices = new ArrayList<BluetoothDevice>(); 323 324 for (BluetoothDevice device: mPanDevices.keySet()) { 325 int panDeviceState = getConnectionState(device); 326 for (int state : states) { 327 if (state == panDeviceState) { 328 panDevices.add(device); 329 break; 330 } 331 } 332 } 333 return panDevices; 334 } 335 336 static protected class ConnectState { ConnectState(byte[] address, int state, int error, int local_role, int remote_role)337 public ConnectState(byte[] address, int state, int error, int local_role, int remote_role) { 338 this.addr = address; 339 this.state = state; 340 this.error = error; 341 this.local_role = local_role; 342 this.remote_role = remote_role; 343 } 344 byte[] addr; 345 int state; 346 int error; 347 int local_role; 348 int remote_role; 349 }; onConnectStateChanged(byte[] address, int state, int error, int local_role, int remote_role)350 private void onConnectStateChanged(byte[] address, int state, int error, int local_role, 351 int remote_role) { 352 if (DBG) { 353 log("onConnectStateChanged: " + state + ", local role:" + local_role + 354 ", remote_role: " + remote_role); 355 } 356 Message msg = mHandler.obtainMessage(MESSAGE_CONNECT_STATE_CHANGED); 357 msg.obj = new ConnectState(address, state, error, local_role, remote_role); 358 mHandler.sendMessage(msg); 359 } onControlStateChanged(int local_role, int state, int error, String ifname)360 private void onControlStateChanged(int local_role, int state, int error, String ifname) { 361 if (DBG) 362 log("onControlStateChanged: " + state + ", error: " + error + ", ifname: " + ifname); 363 if(error == 0) 364 mPanIfName = ifname; 365 } 366 convertHalState(int halState)367 private static int convertHalState(int halState) { 368 switch (halState) { 369 case CONN_STATE_CONNECTED: 370 return BluetoothProfile.STATE_CONNECTED; 371 case CONN_STATE_CONNECTING: 372 return BluetoothProfile.STATE_CONNECTING; 373 case CONN_STATE_DISCONNECTED: 374 return BluetoothProfile.STATE_DISCONNECTED; 375 case CONN_STATE_DISCONNECTING: 376 return BluetoothProfile.STATE_DISCONNECTING; 377 default: 378 Log.e(TAG, "bad pan connection state: " + halState); 379 return BluetoothProfile.STATE_DISCONNECTED; 380 } 381 } 382 handlePanDeviceStateChange(BluetoothDevice device, String iface, int state, int local_role, int remote_role)383 void handlePanDeviceStateChange(BluetoothDevice device, 384 String iface, int state, int local_role, int remote_role) { 385 if(DBG) { 386 Log.d(TAG, "handlePanDeviceStateChange: device: " + device + ", iface: " + iface + 387 ", state: " + state + ", local_role:" + local_role + ", remote_role:" + 388 remote_role); 389 } 390 int prevState; 391 String ifaceAddr = null; 392 BluetoothPanDevice panDevice = mPanDevices.get(device); 393 if (panDevice == null) { 394 prevState = BluetoothProfile.STATE_DISCONNECTED; 395 } else { 396 prevState = panDevice.mState; 397 ifaceAddr = panDevice.mIfaceAddr; 398 } 399 400 // Avoid race condition that gets this class stuck in STATE_DISCONNECTING. While we 401 // are in STATE_CONNECTING, if a BluetoothPan#disconnect call comes in, the original 402 // connect call will put us in STATE_DISCONNECTED. Then, the disconnect completes and 403 // changes the state to STATE_DISCONNECTING. All future calls to BluetoothPan#connect 404 // will fail until the caller explicitly calls BluetoothPan#disconnect. 405 if (prevState == BluetoothProfile.STATE_DISCONNECTED && state == BluetoothProfile.STATE_DISCONNECTING) { 406 Log.d(TAG, "Ignoring state change from " + prevState + " to " + state); 407 return; 408 } 409 410 Log.d(TAG, "handlePanDeviceStateChange preState: " + prevState + " state: " + state); 411 if (prevState == state) return; 412 if (remote_role == BluetoothPan.LOCAL_PANU_ROLE) { 413 if (state == BluetoothProfile.STATE_CONNECTED) { 414 if((!mTetherOn)||(local_role == BluetoothPan.LOCAL_PANU_ROLE)){ 415 Log.d(TAG,"handlePanDeviceStateChange BT tethering is off/Local role is PANU "+ 416 "drop the connection"); 417 disconnectPanNative(Utils.getByteAddress(device)); 418 return; 419 } 420 Log.d(TAG, "handlePanDeviceStateChange LOCAL_NAP_ROLE:REMOTE_PANU_ROLE"); 421 ifaceAddr = enableTethering(iface); 422 if (ifaceAddr == null) Log.e(TAG, "Error seting up tether interface"); 423 424 } else if (state == BluetoothProfile.STATE_DISCONNECTED) { 425 if (ifaceAddr != null) { 426 mBluetoothIfaceAddresses.remove(ifaceAddr); 427 ifaceAddr = null; 428 } 429 } 430 } else if (mNetworkFactory != null) { 431 // PANU Role = reverse Tether 432 Log.d(TAG, "handlePanDeviceStateChange LOCAL_PANU_ROLE:REMOTE_NAP_ROLE state = " + 433 state + ", prevState = " + prevState); 434 if (state == BluetoothProfile.STATE_CONNECTED) { 435 mNetworkFactory.startReverseTether(iface); 436 } else if (state == BluetoothProfile.STATE_DISCONNECTED && 437 (prevState == BluetoothProfile.STATE_CONNECTED || 438 prevState == BluetoothProfile.STATE_DISCONNECTING)) { 439 mNetworkFactory.stopReverseTether(); 440 } 441 } 442 443 if (panDevice == null) { 444 panDevice = new BluetoothPanDevice(state, ifaceAddr, iface, local_role); 445 mPanDevices.put(device, panDevice); 446 } else { 447 panDevice.mState = state; 448 panDevice.mIfaceAddr = ifaceAddr; 449 panDevice.mLocalRole = local_role; 450 panDevice.mIface = iface; 451 } 452 453 /* Notifying the connection state change of the profile before sending the intent for 454 connection state change, as it was causing a race condition, with the UI not being 455 updated with the correct connection state. */ 456 Log.d(TAG, "Pan Device state : device: " + device + " State:" + 457 prevState + "->" + state); 458 notifyProfileConnectionStateChanged(device, BluetoothProfile.PAN, state, prevState); 459 Intent intent = new Intent(BluetoothPan.ACTION_CONNECTION_STATE_CHANGED); 460 intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); 461 intent.putExtra(BluetoothPan.EXTRA_PREVIOUS_STATE, prevState); 462 intent.putExtra(BluetoothPan.EXTRA_STATE, state); 463 intent.putExtra(BluetoothPan.EXTRA_LOCAL_ROLE, local_role); 464 sendBroadcast(intent, BLUETOOTH_PERM); 465 } 466 467 // configured when we start tethering enableTethering(String iface)468 private String enableTethering(String iface) { 469 if (DBG) Log.d(TAG, "updateTetherState:" + iface); 470 471 IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); 472 INetworkManagementService service = INetworkManagementService.Stub.asInterface(b); 473 ConnectivityManager cm = 474 (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); 475 String[] bluetoothRegexs = cm.getTetherableBluetoothRegexs(); 476 477 // bring toggle the interfaces 478 String[] currentIfaces = new String[0]; 479 try { 480 currentIfaces = service.listInterfaces(); 481 } catch (Exception e) { 482 Log.e(TAG, "Error listing Interfaces :" + e); 483 return null; 484 } 485 486 boolean found = false; 487 for (String currIface: currentIfaces) { 488 if (currIface.equals(iface)) { 489 found = true; 490 break; 491 } 492 } 493 494 if (!found) return null; 495 496 String address = createNewTetheringAddressLocked(); 497 if (address == null) return null; 498 499 InterfaceConfiguration ifcg = null; 500 try { 501 ifcg = service.getInterfaceConfig(iface); 502 if (ifcg != null) { 503 InetAddress addr = null; 504 LinkAddress linkAddr = ifcg.getLinkAddress(); 505 if (linkAddr == null || (addr = linkAddr.getAddress()) == null || 506 addr.equals(NetworkUtils.numericToInetAddress("0.0.0.0")) || 507 addr.equals(NetworkUtils.numericToInetAddress("::0"))) { 508 addr = NetworkUtils.numericToInetAddress(address); 509 } 510 ifcg.setInterfaceUp(); 511 ifcg.setLinkAddress(new LinkAddress(addr, BLUETOOTH_PREFIX_LENGTH)); 512 ifcg.clearFlag("running"); 513 // TODO(BT) ifcg.interfaceFlags = ifcg.interfaceFlags.replace(" "," "); 514 service.setInterfaceConfig(iface, ifcg); 515 if (cm.tether(iface) != ConnectivityManager.TETHER_ERROR_NO_ERROR) { 516 Log.e(TAG, "Error tethering "+iface); 517 } 518 } 519 } catch (Exception e) { 520 Log.e(TAG, "Error configuring interface " + iface + ", :" + e); 521 return null; 522 } 523 return address; 524 } 525 createNewTetheringAddressLocked()526 private String createNewTetheringAddressLocked() { 527 if (getConnectedPanDevices().size() == mMaxPanDevices) { 528 if (DBG) Log.d(TAG, "Max PAN device connections reached"); 529 return null; 530 } 531 String address = BLUETOOTH_IFACE_ADDR_START; 532 while (true) { 533 if (mBluetoothIfaceAddresses.contains(address)) { 534 String[] addr = address.split("\\."); 535 Integer newIp = Integer.parseInt(addr[2]) + 1; 536 address = address.replace(addr[2], newIp.toString()); 537 } else { 538 break; 539 } 540 } 541 mBluetoothIfaceAddresses.add(address); 542 return address; 543 } 544 getConnectedPanDevices()545 private List<BluetoothDevice> getConnectedPanDevices() { 546 List<BluetoothDevice> devices = new ArrayList<BluetoothDevice>(); 547 548 for (BluetoothDevice device: mPanDevices.keySet()) { 549 if (getPanDeviceConnectionState(device) == BluetoothProfile.STATE_CONNECTED) { 550 devices.add(device); 551 } 552 } 553 return devices; 554 } 555 getPanDeviceConnectionState(BluetoothDevice device)556 private int getPanDeviceConnectionState(BluetoothDevice device) { 557 BluetoothPanDevice panDevice = mPanDevices.get(device); 558 if (panDevice == null) { 559 return BluetoothProfile.STATE_DISCONNECTED; 560 } 561 return panDevice.mState; 562 } 563 564 @Override dump(StringBuilder sb)565 public void dump(StringBuilder sb) { 566 super.dump(sb); 567 println(sb, "mMaxPanDevices: " + mMaxPanDevices); 568 println(sb, "mPanIfName: " + mPanIfName); 569 println(sb, "mTetherOn: " + mTetherOn); 570 println(sb, "mPanDevices:"); 571 for (BluetoothDevice device : mPanDevices.keySet()) { 572 println(sb, " " + device + " : " + mPanDevices.get(device)); 573 } 574 println(sb, "mBluetoothIfaceAddresses:"); 575 for (String address : mBluetoothIfaceAddresses) { 576 println(sb, " " + address); 577 } 578 } 579 580 private class BluetoothPanDevice { 581 private int mState; 582 private String mIfaceAddr; 583 private String mIface; 584 private int mLocalRole; // Which local role is this PAN device bound to 585 BluetoothPanDevice(int state, String ifaceAddr, String iface, int localRole)586 BluetoothPanDevice(int state, String ifaceAddr, String iface, int localRole) { 587 mState = state; 588 mIfaceAddr = ifaceAddr; 589 mIface = iface; 590 mLocalRole = localRole; 591 } 592 } 593 594 // Constants matching Hal header file bt_hh.h 595 // bthh_connection_state_t 596 private final static int CONN_STATE_CONNECTED = 0; 597 private final static int CONN_STATE_CONNECTING = 1; 598 private final static int CONN_STATE_DISCONNECTED = 2; 599 private final static int CONN_STATE_DISCONNECTING = 3; 600 classInitNative()601 private native static void classInitNative(); initializeNative()602 private native void initializeNative(); cleanupNative()603 private native void cleanupNative(); connectPanNative(byte[] btAddress, int local_role, int remote_role)604 private native boolean connectPanNative(byte[] btAddress, int local_role, int remote_role); disconnectPanNative(byte[] btAddress)605 private native boolean disconnectPanNative(byte[] btAddress); enablePanNative(int local_role)606 private native boolean enablePanNative(int local_role); getPanLocalRoleNative()607 private native int getPanLocalRoleNative(); 608 609 } 610