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