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