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