diff options
author | Danica Chang <danicachang@google.com> | 2010-08-11 14:54:43 -0700 |
---|---|---|
committer | Danica Chang <danicachang@google.com> | 2010-08-18 15:07:50 -0700 |
commit | 6fdd0c6274c81b337ad35b70480f881daf7354c3 (patch) | |
tree | c2ebc20ef5e831e0023660a6ace80ba4783b3996 /core/java/android | |
parent | 5aaeaffdce904dae6e3eaf566dccf52611dffafa (diff) | |
download | frameworks_base-6fdd0c6274c81b337ad35b70480f881daf7354c3.zip frameworks_base-6fdd0c6274c81b337ad35b70480f881daf7354c3.tar.gz frameworks_base-6fdd0c6274c81b337ad35b70480f881daf7354c3.tar.bz2 |
bluetooth tethering
Change-Id: Id6d5fb1922facc7013abc29214d3e1141995b767
Diffstat (limited to 'core/java/android')
-rw-r--r-- | core/java/android/bluetooth/BluetoothDevicePicker.java | 5 | ||||
-rw-r--r-- | core/java/android/bluetooth/BluetoothPan.java | 192 | ||||
-rw-r--r-- | core/java/android/bluetooth/BluetoothUuid.java | 13 | ||||
-rw-r--r-- | core/java/android/bluetooth/IBluetooth.aidl | 7 | ||||
-rw-r--r-- | core/java/android/net/ConnectivityManager.java | 15 | ||||
-rw-r--r-- | core/java/android/net/IConnectivityManager.aidl | 18 | ||||
-rw-r--r-- | core/java/android/server/BluetoothEventLoop.java | 49 | ||||
-rw-r--r-- | core/java/android/server/BluetoothService.java | 215 |
8 files changed, 499 insertions, 15 deletions
diff --git a/core/java/android/bluetooth/BluetoothDevicePicker.java b/core/java/android/bluetooth/BluetoothDevicePicker.java index 05eed0e..7415721 100644 --- a/core/java/android/bluetooth/BluetoothDevicePicker.java +++ b/core/java/android/bluetooth/BluetoothDevicePicker.java @@ -63,4 +63,9 @@ public interface BluetoothDevicePicker { public static final int FILTER_TYPE_AUDIO = 1; /** Ask device picker to show BT devices that support Object Transfer */ public static final int FILTER_TYPE_TRANSFER = 2; + /** Ask device picker to show BT devices that support + * Personal Area Networking User (PANU) profile*/ + public static final int FILTER_TYPE_PANU = 3; + /** Ask device picker to show BT devices that support Network Access Point (NAP) profile */ + public static final int FILTER_TYPE_NAP = 4; } diff --git a/core/java/android/bluetooth/BluetoothPan.java b/core/java/android/bluetooth/BluetoothPan.java new file mode 100644 index 0000000..952765d --- /dev/null +++ b/core/java/android/bluetooth/BluetoothPan.java @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.bluetooth; + +import android.annotation.SdkConstant; +import android.annotation.SdkConstant.SdkConstantType; +import android.content.Context; +import android.os.ServiceManager; +import android.os.RemoteException; +import android.os.IBinder; +import android.util.Log; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/** + * @hide + */ +public final class BluetoothPan { + private static final String TAG = "BluetoothPan"; + private static final boolean DBG = false; + + /** int extra for ACTION_PAN_STATE_CHANGED */ + public static final String EXTRA_PAN_STATE = + "android.bluetooth.pan.extra.STATE"; + /** int extra for ACTION_PAN_STATE_CHANGED */ + public static final String EXTRA_PREVIOUS_PAN_STATE = + "android.bluetooth.pan.extra.PREVIOUS_STATE"; + + /** Indicates the state of an PAN device has changed. + * This intent will always contain EXTRA_DEVICE_STATE, + * EXTRA_PREVIOUS_DEVICE_STATE and BluetoothDevice.EXTRA_DEVICE + * extras. + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_PAN_STATE_CHANGED = + "android.bluetooth.pan.action.STATE_CHANGED"; + + public static final String NAP_ROLE = "nap"; + public static final String NAP_BRIDGE = "pan1"; + + public static final int MAX_CONNECTIONS = 7; + + public static final int STATE_DISCONNECTED = 0; + public static final int STATE_CONNECTING = 1; + public static final int STATE_CONNECTED = 2; + public static final int STATE_DISCONNECTING = 3; + + private final IBluetooth mService; + private final Context mContext; + + /** + * Create a BluetoothPan proxy object for interacting with the local + * Bluetooth Pan service. + * @param c Context + */ + public BluetoothPan(Context c) { + mContext = c; + + IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_SERVICE); + if (b != null) { + mService = IBluetooth.Stub.asInterface(b); + } else { + Log.w(TAG, "Bluetooth Service not available!"); + + // Instead of throwing an exception which prevents people from going + // into Wireless settings in the emulator. Let it crash later + // when it is actually used. + mService = null; + } + } + + /** + * Initiate a PAN connection. + * + * This function returns false on error and true if the connection + * attempt is being made. + * + * Listen for {@link #ACTION_PAN_STATE_CHANGED} to find out when the + * connection is completed. + * + * @param device Remote BT device. + * @return false on immediate error, true otherwise + * @hide + */ + public boolean connect(BluetoothDevice device) { + if (DBG) log("connect(" + device + ")"); + try { + return mService.connectPanDevice(device); + } catch (RemoteException e) { + Log.e(TAG, "", e); + return false; + } + } + + /** + * Initiate disconnect from PAN. + * + * This function return false on error and true if the disconnection + * attempt is being made. + * + * Listen for {@link #ACTION_PAN_STATE_CHANGED} to find out when + * disconnect is completed. + * + * @param device Remote BT device. + * @return false on immediate error, true otherwise + * @hide + */ + public boolean disconnect(BluetoothDevice device) { + if (DBG) log("disconnect(" + device + ")"); + try { + return mService.disconnectPanDevice(device); + } catch (RemoteException e) { + Log.e(TAG, "", e); + return false; + } + } + + /** Get the state of a PAN Device. + * + * This function returns an int representing the state of the PAN connection + * + * @param device Remote BT device. + * @return The current state of the PAN Device + * @hide + */ + public int getPanDeviceState(BluetoothDevice device) { + if (DBG) log("getPanDeviceState(" + device + ")"); + try { + return mService.getPanDeviceState(device); + } catch (RemoteException e) { + Log.e(TAG, "", e); + return STATE_DISCONNECTED; + } + } + + /** Returns a set of all the connected PAN Devices + * + * Does not include devices that are currently connecting or disconnecting + * + * @return a unmodifiable set of connected PAN Devices, or null on error. + * @hide + */ + public Set<BluetoothDevice> getConnectedDevices() { + if (DBG) log("getConnectedDevices"); + try { + return Collections.unmodifiableSet( + new HashSet<BluetoothDevice>( + Arrays.asList(mService.getConnectedPanDevices()))); + } catch (RemoteException e) { + Log.e(TAG, "", e); + return null; + } + } + + private static void log(String msg) { + Log.d(TAG, msg); + } + + public void setBluetoothTethering(boolean value, String uuid, String bridge) { + try { + mService.setBluetoothTethering(value, uuid, bridge); + } catch (RemoteException e) { + Log.e(TAG, "", e); + } + } + + public boolean isTetheringOn() { + try { + return mService.isTetheringOn(); + } catch (RemoteException e) { + Log.e(TAG, "", e); + return false; + } + } +} diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java index f1ee907..fb3dfe4 100644 --- a/core/java/android/bluetooth/BluetoothUuid.java +++ b/core/java/android/bluetooth/BluetoothUuid.java @@ -51,10 +51,14 @@ public final class BluetoothUuid { ParcelUuid.fromString("00001105-0000-1000-8000-00805f9b34fb"); public static final ParcelUuid Hid = ParcelUuid.fromString("00001124-0000-1000-8000-00805f9b34fb"); + public static final ParcelUuid PANU = + ParcelUuid.fromString("00001115-0000-1000-8000-00805F9B34FB"); + public static final ParcelUuid NAP = + ParcelUuid.fromString("00001116-0000-1000-8000-00805F9B34FB"); public static final ParcelUuid[] RESERVED_UUIDS = { AudioSink, AudioSource, AdvAudioDist, HSP, Handsfree, AvrcpController, AvrcpTarget, - ObexObjectPush}; + ObexObjectPush, PANU, NAP}; public static boolean isAudioSource(ParcelUuid uuid) { return uuid.equals(AudioSource); @@ -88,6 +92,13 @@ public final class BluetoothUuid { return uuid.equals(Hid); } + public static boolean isPANU(ParcelUuid uuid) { + return uuid.equals(PANU); + } + + public static boolean isNAP(ParcelUuid uuid) { + return uuid.equals(NAP); + } /** * Returns true if ParcelUuid is present in uuidArray * diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl index 75f093c..f8f678b 100644 --- a/core/java/android/bluetooth/IBluetooth.aidl +++ b/core/java/android/bluetooth/IBluetooth.aidl @@ -81,4 +81,11 @@ interface IBluetooth int getInputDeviceState(in BluetoothDevice device); boolean setInputDevicePriority(in BluetoothDevice device, int priority); int getInputDevicePriority(in BluetoothDevice device); + + boolean isTetheringOn(); + void setBluetoothTethering(boolean value, String uuid, String bridge); + int getPanDeviceState(in BluetoothDevice device); + BluetoothDevice[] getConnectedPanDevices(); + boolean connectPanDevice(in BluetoothDevice device); + boolean disconnectPanDevice(in BluetoothDevice device); } diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 6335296..8d1a04c 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -324,14 +324,14 @@ public class ConnectivityManager * <p> * All applications that have background services that use the network * should listen to {@link #ACTION_BACKGROUND_DATA_SETTING_CHANGED}. - * + * * @return Whether background data usage is allowed. */ public boolean getBackgroundDataSetting() { try { return mService.getBackgroundDataSetting(); } catch (RemoteException e) { - // Err on the side of safety + // Err on the side of safety return false; } } @@ -489,6 +489,17 @@ public class ConnectivityManager } } + /** + * {@hide} + */ + public String[] getTetherableBluetoothRegexs() { + try { + return mService.getTetherableBluetoothRegexs(); + } catch (RemoteException e) { + return new String[0]; + } + } + /** {@hide} */ public static final int TETHER_ERROR_NO_ERROR = 0; /** {@hide} */ diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 5a14cc9..1d57019 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -1,16 +1,16 @@ /** * Copyright (c) 2008, The Android Open Source Project * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and * limitations under the License. */ @@ -73,5 +73,7 @@ interface IConnectivityManager String[] getTetherableWifiRegexs(); + String[] getTetherableBluetoothRegexs(); + void requestNetworkTransitionWakelock(in String forWhom); } diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java index eb9b62b..9948060 100644 --- a/core/java/android/server/BluetoothEventLoop.java +++ b/core/java/android/server/BluetoothEventLoop.java @@ -21,6 +21,7 @@ import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothClass; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothInputDevice; +import android.bluetooth.BluetoothPan; import android.bluetooth.BluetoothUuid; import android.content.Context; import android.content.Intent; @@ -365,7 +366,8 @@ class BluetoothEventLoop { return; } if (DBG) { - log("Device property changed:" + address + "property:" + name); + log("Device property changed: " + address + " property: " + + name + " value: " + propValues[1]); } BluetoothDevice device = mAdapter.getRemoteDevice(address); if (name.equals("Name")) { @@ -442,6 +444,25 @@ class BluetoothEventLoop { mBluetoothService.handleInputDevicePropertyChange(address, state); } + private void onPanDevicePropertyChanged(String deviceObjectPath, String[] propValues) { + String name = propValues[0]; + String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath); + if (address == null) { + Log.e(TAG, "onPanDevicePropertyChanged: Address of the remote device in null"); + return; + } + if (DBG) { + log("Pan Device property changed: " + address + " property: " + + name + " value: "+ propValues[1]); + } + BluetoothDevice device = mAdapter.getRemoteDevice(address); + if (name.equals("Connected")) { + int state = propValues[1].equals("true") ? BluetoothInputDevice.STATE_CONNECTED : + BluetoothInputDevice.STATE_DISCONNECTED; + mBluetoothService.handlePanDeviceStateChange(device, state); + } + } + private String checkPairingRequestAndGetAddress(String objectPath, int nativeData) { String address = mBluetoothService.getAddressFromObjectPath(objectPath); if (address == null) { @@ -623,6 +644,8 @@ class BluetoothEventLoop { } else { Log.i(TAG, "Rejecting incoming HID connection from " + address); } + } else if (BluetoothUuid.isNAP(uuid)){ + authorized = true; } else { Log.i(TAG, "Rejecting incoming " + deviceUuid + " connection from " + address); } @@ -713,6 +736,30 @@ class BluetoothEventLoop { } } + private void onPanDeviceConnectionResult(String path, boolean result) { + log ("onPanDeviceConnectionResult " + path + " " + result); + // Success case gets handled by Property Change signal + if (!result) { + String address = mBluetoothService.getAddressFromObjectPath(path); + if (address == null) return; + + boolean connected = false; + BluetoothDevice device = mAdapter.getRemoteDevice(address); + int state = mBluetoothService.getPanDeviceState(device); + if (state == BluetoothPan.STATE_CONNECTING) { + connected = false; + } else if (state == BluetoothPan.STATE_DISCONNECTING) { + connected = true; + } else { + Log.e(TAG, "Error onPanDeviceConnectionResult. State is: " + + state + " result: "+ result); + } + int newState = connected? BluetoothPan.STATE_CONNECTED : + BluetoothPan.STATE_DISCONNECTED; + mBluetoothService.handlePanDeviceStateChange(device, newState); + } + } + private void onRestartRequired() { if (mBluetoothService.isEnabled()) { Log.e(TAG, "*** A serious error occured (did bluetoothd crash?) - " + diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java index acfc0d7..ab78aeb 100644 --- a/core/java/android/server/BluetoothService.java +++ b/core/java/android/server/BluetoothService.java @@ -24,28 +24,30 @@ package android.server; -import android.bluetooth.BluetoothA2dp; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothClass; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHeadset; import android.bluetooth.BluetoothDeviceProfileState; +import android.bluetooth.BluetoothPan; import android.bluetooth.BluetoothProfileState; import android.bluetooth.BluetoothInputDevice; import android.bluetooth.BluetoothSocket; import android.bluetooth.BluetoothUuid; import android.bluetooth.IBluetooth; import android.bluetooth.IBluetoothCallback; -import android.bluetooth.IBluetoothHeadset; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; +import android.net.ConnectivityManager; +import android.net.InterfaceConfiguration; import android.os.Binder; import android.os.Handler; import android.os.IBinder; +import android.os.INetworkManagementService; import android.os.Message; import android.os.ParcelUuid; import android.os.RemoteException; @@ -89,6 +91,7 @@ public class BluetoothService extends IBluetooth.Stub { private int mBluetoothState; private boolean mRestart = false; // need to call enable() after disable() private boolean mIsDiscovering; + private boolean mTetheringOn; private BluetoothAdapter mAdapter; // constant after init() private final BondState mBondState = new BondState(); // local cache of bondings @@ -109,6 +112,10 @@ public class BluetoothService extends IBluetooth.Stub { private static final int MESSAGE_UUID_INTENT = 3; private static final int MESSAGE_DISCOVERABLE_TIMEOUT = 4; + private ArrayList<String> mBluetoothIfaceAddresses; + private static final String BLUETOOTH_NEAR_IFACE_ADDR_PREFIX= "192.168.44."; + private static final String BLUETOOTH_NETMASK = "255.255.255.0"; + // The timeout used to sent the UUIDs Intent // This timeout should be greater than the page timeout private static final int UUID_INTENT_DELAY = 6000; @@ -136,6 +143,7 @@ public class BluetoothService extends IBluetooth.Stub { private BluetoothA2dpService mA2dpService; private final HashMap<BluetoothDevice, Integer> mInputDevices; + private final HashMap<BluetoothDevice, Integer> mPanDevices; private static String mDockAddress; private String mDockPin; @@ -187,6 +195,7 @@ public class BluetoothService extends IBluetooth.Stub { mBluetoothState = BluetoothAdapter.STATE_OFF; mIsDiscovering = false; + mTetheringOn = false; mAdapterProperties = new HashMap<String, String>(); mDeviceProperties = new HashMap<String, Map<String,String>>(); @@ -199,6 +208,12 @@ public class BluetoothService extends IBluetooth.Stub { mHfpProfileState = new BluetoothProfileState(mContext, BluetoothProfileState.HFP); mHidProfileState = new BluetoothProfileState(mContext, BluetoothProfileState.HID); + // Can tether to up to 7 devices + mBluetoothIfaceAddresses = new ArrayList<String>(BluetoothPan.MAX_CONNECTIONS); + for (int i=1; i <= BluetoothPan.MAX_CONNECTIONS; i++) { + mBluetoothIfaceAddresses.add(BLUETOOTH_NEAR_IFACE_ADDR_PREFIX + i); + } + mHfpProfileState.start(); mA2dpProfileState.start(); mHidProfileState.start(); @@ -209,6 +224,7 @@ public class BluetoothService extends IBluetooth.Stub { filter.addAction(Intent.ACTION_DOCK_EVENT); mContext.registerReceiver(mReceiver, filter); mInputDevices = new HashMap<BluetoothDevice, Integer>(); + mPanDevices = new HashMap<BluetoothDevice, Integer>(); } public static synchronized String readDockBluetoothAddress() { @@ -336,6 +352,7 @@ public class BluetoothService extends IBluetooth.Stub { } setBluetoothState(BluetoothAdapter.STATE_TURNING_OFF); mHandler.removeMessages(MESSAGE_REGISTER_SDP_RECORDS); + setBluetoothTethering(false, BluetoothPan.NAP_ROLE, BluetoothPan.NAP_BRIDGE); // Allow 3 seconds for profiles to gracefully disconnect // TODO: Introduce a callback mechanism so that each profile can notify @@ -1235,6 +1252,194 @@ public class BluetoothService extends IBluetooth.Stub { return sp.contains(SHARED_PREFERENCE_DOCK_ADDRESS + address); } + public synchronized boolean isTetheringOn() { + return mTetheringOn; + } + + public synchronized void setBluetoothTethering(boolean value, String uuid, String bridge) { + mTetheringOn = value; + if (!value) { + disconnectPan(); + } + setBluetoothTetheringNative(value, uuid, bridge); + } + + public synchronized int getPanDeviceState(BluetoothDevice device) { + mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); + + if (mPanDevices.get(device) == null) { + return BluetoothPan.STATE_DISCONNECTED; + } + return mPanDevices.get(device); + } + + public synchronized boolean connectPanDevice(BluetoothDevice device) { + mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, + "Need BLUETOOTH_ADMIN permission"); + + String objectPath = getObjectPathFromAddress(device.getAddress()); + if (DBG) log("connect PAN(" + objectPath + ")"); + if (getPanDeviceState(device) != BluetoothPan.STATE_DISCONNECTED) { + log (device + " already connected to PAN"); + } + + int connectedCount = 0; + for (BluetoothDevice BTdevice: mPanDevices.keySet()) { + if (getPanDeviceState(BTdevice) == BluetoothPan.STATE_CONNECTED) { + connectedCount ++; + } + } + if (connectedCount > 8) { + log (device + " could not connect to PAN because 8 other devices are already connected"); + return false; + } + + handlePanDeviceStateChange(device, BluetoothPan.STATE_CONNECTING); + if (connectPanDeviceNative(objectPath, "nap", "panu")) { + log ("connecting to PAN"); + return true; + } else { + handlePanDeviceStateChange(device, BluetoothPan.STATE_DISCONNECTED); + log ("could not connect to PAN"); + return false; + } + } + + private synchronized boolean disconnectPan() { + mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); + if (DBG) log("disconnect all PAN devices"); + + for (BluetoothDevice device: mPanDevices.keySet()) { + if (getPanDeviceState(device) == BluetoothPan.STATE_CONNECTED) { + if (!disconnectPanDevice(device)) { + log ("could not disconnect Pan Device "+device.getAddress()); + return false; + } + } + } + return true; + } + + public synchronized BluetoothDevice[] getConnectedPanDevices() { + mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); + + Set<BluetoothDevice> devices = new HashSet<BluetoothDevice>(); + for (BluetoothDevice device: mPanDevices.keySet()) { + if (getPanDeviceState(device) == BluetoothPan.STATE_CONNECTED) { + devices.add(device); + } + } + return devices.toArray(new BluetoothDevice[devices.size()]); + } + + public synchronized boolean disconnectPanDevice(BluetoothDevice device) { + mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, + "Need BLUETOOTH_ADMIN permission"); + String objectPath = getObjectPathFromAddress(device.getAddress()); + if (DBG) log("disconnect PAN(" + objectPath + ")"); + if (getPanDeviceState(device) != BluetoothPan.STATE_CONNECTED) { + log (device + " already disconnected from PAN"); + } + handlePanDeviceStateChange(device, BluetoothPan.STATE_DISCONNECTING); + return disconnectPanDeviceNative(objectPath); + } + + /*package*/ void handlePanDeviceStateChange(BluetoothDevice device, int state) { + int prevState; + if (mPanDevices.get(device) == null) { + prevState = BluetoothPan.STATE_DISCONNECTED; + } else { + prevState = mPanDevices.get(device); + } + if (prevState == state) return; + + mPanDevices.put(device, state); + + if (state == BluetoothPan.STATE_CONNECTED) { + updateTetherState(true); + } + + Intent intent = new Intent(BluetoothPan.ACTION_PAN_STATE_CHANGED); + intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); + intent.putExtra(BluetoothPan.EXTRA_PREVIOUS_PAN_STATE, prevState); + intent.putExtra(BluetoothPan.EXTRA_PAN_STATE, state); + mContext.sendBroadcast(intent, BLUETOOTH_PERM); + + if (DBG) log("Pan Device state : device: " + device + " State:" + prevState + "->" + state); + + } + + // configured when we start tethering and unconfig'd on error or conclusion + private boolean updateTetherState(boolean enabled) { + Log.d(TAG, "configureBluetoothIface(" + enabled + ")"); + + IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); + INetworkManagementService service = INetworkManagementService.Stub.asInterface(b); + ConnectivityManager cm = + (ConnectivityManager)mContext.getSystemService(Context.CONNECTIVITY_SERVICE); + String[] bluetoothRegexs = cm.getTetherableBluetoothRegexs(); + + // bring toggle the interfaces + String[] ifaces = new String[0]; + try { + ifaces = service.listInterfaces(); + } catch (Exception e) { + Log.e(TAG, "Error listing Interfaces :" + e); + return false; + } + + ArrayList<String> ifaceAddresses = (ArrayList<String>) mBluetoothIfaceAddresses.clone(); + for (String iface : ifaces) { + for (String regex : bluetoothRegexs) { + if (iface.matches(regex)) { + InterfaceConfiguration ifcg = null; + try { + ifcg = service.getInterfaceConfig(iface); + if (ifcg != null) { + if (enabled) { + String[] addr = BLUETOOTH_NETMASK.split("\\."); + ifcg.netmask = (Integer.parseInt(addr[0]) << 24) + + (Integer.parseInt(addr[1]) << 16) + + (Integer.parseInt(addr[2]) << 8) + + (Integer.parseInt(addr[3])); + if (ifcg.ipAddr == 0 && !ifaceAddresses.isEmpty()) { + addr = ifaceAddresses.remove(0).split("\\."); + ifcg.ipAddr = (Integer.parseInt(addr[0]) << 24) + + (Integer.parseInt(addr[1]) << 16) + + (Integer.parseInt(addr[2]) << 8) + + (Integer.parseInt(addr[3])); + } else { + String IfaceAddress = + String.valueOf(ifcg.ipAddr >>> 24) + "." + + String.valueOf((ifcg.ipAddr & 0x00FF0000) >>> 16) + "." + + String.valueOf((ifcg.ipAddr & 0x0000FF00) >>> 8) + "." + + String.valueOf(ifcg.ipAddr & 0x000000FF); + ifaceAddresses.remove(IfaceAddress); + } + ifcg.interfaceFlags = ifcg.interfaceFlags.replace("down", "up"); + } else { + ifcg.interfaceFlags = ifcg.interfaceFlags.replace("up", "down"); + } + ifcg.interfaceFlags = ifcg.interfaceFlags.replace("running", ""); + ifcg.interfaceFlags = ifcg.interfaceFlags.replace(" "," "); + service.setInterfaceConfig(iface, ifcg); + if (enabled) { + if (cm.tether(iface) != ConnectivityManager.TETHER_ERROR_NO_ERROR) { + Log.e(TAG, "Error tethering "+ifaces); + } + } + } + } catch (Exception e) { + Log.e(TAG, "Error configuring interface " + iface + ", :" + e); + return false; + } + } + } + } + + return true; + } + public synchronized boolean connectInputDevice(BluetoothDevice device) { mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission"); @@ -1418,7 +1623,7 @@ public class BluetoothService extends IBluetooth.Stub { if (updateRemoteDevicePropertiesCache(address)) return getRemoteDeviceProperty(address, property); } - Log.e(TAG, "getRemoteDeviceProperty: " + property + "not present:" + address); + Log.e(TAG, "getRemoteDeviceProperty: " + property + " not present: " + address); return null; } @@ -2281,4 +2486,8 @@ public class BluetoothService extends IBluetooth.Stub { private native boolean setLinkTimeoutNative(String path, int num_slots); private native boolean connectInputDeviceNative(String path); private native boolean disconnectInputDeviceNative(String path); + + private native boolean setBluetoothTetheringNative(boolean value, String nap, String bridge); + private native boolean connectPanDeviceNative(String path, String srcRole, String dstRole); + private native boolean disconnectPanDeviceNative(String path); } |