Merge "bluetooth tethering"
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
192
core/java/android/bluetooth/BluetoothPan.java
Normal file
192
core/java/android/bluetooth/BluetoothPan.java
Normal file
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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} */
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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?) - " +
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -73,6 +73,12 @@ static Properties input_properties[] = {
|
||||
{"Connected", DBUS_TYPE_BOOLEAN},
|
||||
};
|
||||
|
||||
static Properties pan_properties[] = {
|
||||
{"Connected", DBUS_TYPE_BOOLEAN},
|
||||
{"Interface", DBUS_TYPE_STRING},
|
||||
{"UUID", DBUS_TYPE_STRING},
|
||||
};
|
||||
|
||||
typedef union {
|
||||
char *str_val;
|
||||
int int_val;
|
||||
@@ -191,6 +197,7 @@ dbus_bool_t dbus_func_args_async(JNIEnv *env,
|
||||
dbus_bool_t ret;
|
||||
va_list lst;
|
||||
va_start(lst, first_arg_type);
|
||||
|
||||
ret = dbus_func_args_async_valist(env, conn,
|
||||
timeout_ms,
|
||||
reply, user, nat,
|
||||
@@ -708,6 +715,11 @@ jobjectArray parse_input_property_change(JNIEnv *env, DBusMessage *msg) {
|
||||
sizeof(input_properties) / sizeof(Properties));
|
||||
}
|
||||
|
||||
jobjectArray parse_pan_property_change(JNIEnv *env, DBusMessage *msg) {
|
||||
return parse_property_change(env, msg, (Properties *) &pan_properties,
|
||||
sizeof(pan_properties) / sizeof(Properties));
|
||||
}
|
||||
|
||||
jobjectArray parse_adapter_properties(JNIEnv *env, DBusMessageIter *iter) {
|
||||
return parse_properties(env, iter, (Properties *) &adapter_properties,
|
||||
sizeof(adapter_properties) / sizeof(Properties));
|
||||
|
||||
@@ -164,6 +164,7 @@ jobjectArray parse_remote_device_property_change(JNIEnv *env, DBusMessage *msg);
|
||||
jobjectArray parse_adapter_property_change(JNIEnv *env, DBusMessage *msg);
|
||||
jobjectArray parse_input_properties(JNIEnv *env, DBusMessageIter *iter);
|
||||
jobjectArray parse_input_property_change(JNIEnv *env, DBusMessage *msg);
|
||||
jobjectArray parse_pan_property_change(JNIEnv *env, DBusMessage *msg);
|
||||
void append_variant(DBusMessageIter *iter, int type, void *val);
|
||||
int get_bdaddr(const char *str, bdaddr_t *ba);
|
||||
void get_bdaddr_as_string(const bdaddr_t *ba, char *str);
|
||||
|
||||
@@ -66,6 +66,8 @@ static jmethodID method_onAgentCancel;
|
||||
|
||||
static jmethodID method_onInputDevicePropertyChanged;
|
||||
static jmethodID method_onInputDeviceConnectionResult;
|
||||
static jmethodID method_onPanDevicePropertyChanged;
|
||||
static jmethodID method_onPanDeviceConnectionResult;
|
||||
|
||||
typedef event_loop_native_data_t native_data_t;
|
||||
|
||||
@@ -120,9 +122,13 @@ static void classInitNative(JNIEnv* env, jclass clazz) {
|
||||
method_onDisplayPasskey = env->GetMethodID(clazz, "onDisplayPasskey",
|
||||
"(Ljava/lang/String;II)V");
|
||||
method_onInputDevicePropertyChanged = env->GetMethodID(clazz, "onInputDevicePropertyChanged",
|
||||
"(Ljava/lang/String;[Ljava/lang/String;)V");
|
||||
"(Ljava/lang/String;[Ljava/lang/String;)V");
|
||||
method_onInputDeviceConnectionResult = env->GetMethodID(clazz, "onInputDeviceConnectionResult",
|
||||
"(Ljava/lang/String;Z)V");
|
||||
"(Ljava/lang/String;Z)V");
|
||||
method_onPanDevicePropertyChanged = env->GetMethodID(clazz, "onPanDevicePropertyChanged",
|
||||
"(Ljava/lang/String;[Ljava/lang/String;)V");
|
||||
method_onPanDeviceConnectionResult = env->GetMethodID(clazz, "onPanDeviceConnectionResult",
|
||||
"(Ljava/lang/String;Z)V");
|
||||
|
||||
field_mNativeData = env->GetFieldID(clazz, "mNativeData", "I");
|
||||
#endif
|
||||
@@ -890,7 +896,23 @@ static DBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg,
|
||||
LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
|
||||
}
|
||||
goto success;
|
||||
}
|
||||
} else if (dbus_message_is_signal(msg,
|
||||
"org.bluez.Network",
|
||||
"PropertyChanged")) {
|
||||
|
||||
jobjectArray str_array =
|
||||
parse_pan_property_change(env, msg);
|
||||
if (str_array != NULL) {
|
||||
const char *c_path = dbus_message_get_path(msg);
|
||||
env->CallVoidMethod(nat->me,
|
||||
method_onPanDevicePropertyChanged,
|
||||
env->NewStringUTF(c_path),
|
||||
str_array);
|
||||
} else {
|
||||
LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
|
||||
}
|
||||
goto success;
|
||||
}
|
||||
|
||||
ret = a2dp_event_filter(msg, env);
|
||||
env->PopLocalFrame(NULL);
|
||||
@@ -1273,6 +1295,31 @@ void onInputDeviceConnectionResult(DBusMessage *msg, void *user, void *n) {
|
||||
free(user);
|
||||
}
|
||||
|
||||
void onPanDeviceConnectionResult(DBusMessage *msg, void *user, void *n) {
|
||||
LOGV(__FUNCTION__);
|
||||
|
||||
native_data_t *nat = (native_data_t *)n;
|
||||
const char *path = (const char *)user;
|
||||
DBusError err;
|
||||
dbus_error_init(&err);
|
||||
JNIEnv *env;
|
||||
nat->vm->GetEnv((void**)&env, nat->envVer);
|
||||
|
||||
bool result = JNI_TRUE;
|
||||
if (dbus_set_error_from_message(&err, msg)) {
|
||||
LOG_AND_FREE_DBUS_ERROR(&err);
|
||||
result = JNI_FALSE;
|
||||
}
|
||||
LOGV("... Pan Device Path = %s, result = %d", path, result);
|
||||
jstring jPath = env->NewStringUTF(path);
|
||||
env->CallVoidMethod(nat->me,
|
||||
method_onPanDeviceConnectionResult,
|
||||
jPath,
|
||||
result);
|
||||
env->DeleteLocalRef(jPath);
|
||||
free(user);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static JNINativeMethod sMethods[] = {
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
#define DBUS_ADAPTER_IFACE BLUEZ_DBUS_BASE_IFC ".Adapter"
|
||||
#define DBUS_DEVICE_IFACE BLUEZ_DBUS_BASE_IFC ".Device"
|
||||
#define DBUS_INPUT_IFACE BLUEZ_DBUS_BASE_IFC ".Input"
|
||||
#define DBUS_NETWORK_IFACE BLUEZ_DBUS_BASE_IFC ".Network"
|
||||
#define DBUS_NETWORKSERVER_IFACE BLUEZ_DBUS_BASE_IFC ".NetworkServer"
|
||||
|
||||
|
||||
#define LOG_TAG "BluetoothService.cpp"
|
||||
|
||||
@@ -71,6 +74,8 @@ void onCreatePairedDeviceResult(DBusMessage *msg, void *user, void *nat);
|
||||
void onDiscoverServicesResult(DBusMessage *msg, void *user, void *nat);
|
||||
void onCreateDeviceResult(DBusMessage *msg, void *user, void *nat);
|
||||
void onInputDeviceConnectionResult(DBusMessage *msg, void *user, void *nat);
|
||||
void onConnectPanResult(DBusMessage *msg, void *user, void *n);
|
||||
void onPanDeviceConnectionResult(DBusMessage *msg, void *user, void *nat);
|
||||
|
||||
|
||||
/** Get native data stored in the opaque (Java code maintained) pointer mNativeData
|
||||
@@ -939,6 +944,105 @@ static jboolean disconnectInputDeviceNative(JNIEnv *env, jobject object,
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
static jboolean setBluetoothTetheringNative(JNIEnv *env, jobject object, jboolean value,
|
||||
jstring src_role, jstring bridge) {
|
||||
LOGV(__FUNCTION__);
|
||||
#ifdef HAVE_BLUETOOTH
|
||||
native_data_t *nat = get_native_data(env, object);
|
||||
if (nat) {
|
||||
DBusMessage *reply;
|
||||
const char *c_role = env->GetStringUTFChars(src_role, NULL);
|
||||
const char *c_bridge = env->GetStringUTFChars(bridge, NULL);
|
||||
if (value) {
|
||||
LOGE("setBluetoothTetheringNative true");
|
||||
reply = dbus_func_args(env, nat->conn,
|
||||
get_adapter_path(env, object),
|
||||
DBUS_NETWORKSERVER_IFACE,
|
||||
"Register",
|
||||
DBUS_TYPE_STRING, &c_role,
|
||||
DBUS_TYPE_STRING, &c_bridge,
|
||||
DBUS_TYPE_INVALID);
|
||||
} else {
|
||||
LOGE("setBluetoothTetheringNative false");
|
||||
reply = dbus_func_args(env, nat->conn,
|
||||
get_adapter_path(env, object),
|
||||
DBUS_NETWORKSERVER_IFACE,
|
||||
"Unregister",
|
||||
DBUS_TYPE_STRING, &c_role,
|
||||
DBUS_TYPE_INVALID);
|
||||
}
|
||||
env->ReleaseStringUTFChars(src_role, c_role);
|
||||
env->ReleaseStringUTFChars(bridge, c_bridge);
|
||||
return reply ? JNI_TRUE : JNI_FALSE;
|
||||
}
|
||||
#endif
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
static jboolean connectPanDeviceNative(JNIEnv *env, jobject object, jstring path,
|
||||
jstring srcRole, jstring dstRole) {
|
||||
LOGV(__FUNCTION__);
|
||||
#ifdef HAVE_BLUETOOTH
|
||||
LOGE("connectPanDeviceNative");
|
||||
native_data_t *nat = get_native_data(env, object);
|
||||
jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
|
||||
struct event_loop_native_data_t *eventLoopNat =
|
||||
get_EventLoop_native_data(env, eventLoop);
|
||||
|
||||
if (nat && eventLoopNat) {
|
||||
const char *c_path = env->GetStringUTFChars(path, NULL);
|
||||
const char *src = env->GetStringUTFChars(srcRole, NULL);
|
||||
const char *dst = env->GetStringUTFChars(dstRole, NULL);
|
||||
|
||||
int len = env->GetStringLength(path) + 1;
|
||||
char *context_path = (char *)calloc(len, sizeof(char));
|
||||
strlcpy(context_path, c_path, len); // for callback
|
||||
|
||||
bool ret = dbus_func_args_async(env, nat->conn, -1,onPanDeviceConnectionResult,
|
||||
context_path, eventLoopNat, c_path,
|
||||
DBUS_NETWORK_IFACE, "Connect",
|
||||
DBUS_TYPE_STRING, &src,
|
||||
DBUS_TYPE_STRING, &dst,
|
||||
DBUS_TYPE_INVALID);
|
||||
|
||||
env->ReleaseStringUTFChars(path, c_path);
|
||||
env->ReleaseStringUTFChars(srcRole, src);
|
||||
env->ReleaseStringUTFChars(dstRole, dst);
|
||||
return ret ? JNI_TRUE : JNI_FALSE;
|
||||
}
|
||||
#endif
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
static jboolean disconnectPanDeviceNative(JNIEnv *env, jobject object,
|
||||
jstring path) {
|
||||
LOGV(__FUNCTION__);
|
||||
#ifdef HAVE_BLUETOOTH
|
||||
LOGE("disconnectPanDeviceNative");
|
||||
native_data_t *nat = get_native_data(env, object);
|
||||
jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
|
||||
struct event_loop_native_data_t *eventLoopNat =
|
||||
get_EventLoop_native_data(env, eventLoop);
|
||||
|
||||
if (nat && eventLoopNat) {
|
||||
const char *c_path = env->GetStringUTFChars(path, NULL);
|
||||
|
||||
int len = env->GetStringLength(path) + 1;
|
||||
char *context_path = (char *)calloc(len, sizeof(char));
|
||||
strlcpy(context_path, c_path, len); // for callback
|
||||
|
||||
bool ret = dbus_func_args_async(env, nat->conn, -1,onPanDeviceConnectionResult,
|
||||
context_path, eventLoopNat, c_path,
|
||||
DBUS_NETWORK_IFACE, "Disconnect",
|
||||
DBUS_TYPE_INVALID);
|
||||
|
||||
env->ReleaseStringUTFChars(path, c_path);
|
||||
return ret ? JNI_TRUE : JNI_FALSE;
|
||||
}
|
||||
#endif
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
static JNINativeMethod sMethods[] = {
|
||||
/* name, signature, funcPtr */
|
||||
{"classInitNative", "()V", (void*)classInitNative},
|
||||
@@ -987,8 +1091,15 @@ static JNINativeMethod sMethods[] = {
|
||||
// HID functions
|
||||
{"connectInputDeviceNative", "(Ljava/lang/String;)Z", (void *)connectInputDeviceNative},
|
||||
{"disconnectInputDeviceNative", "(Ljava/lang/String;)Z", (void *)disconnectInputDeviceNative},
|
||||
|
||||
{"setBluetoothTetheringNative", "(ZLjava/lang/String;Ljava/lang/String;)Z",
|
||||
(void *)setBluetoothTetheringNative},
|
||||
{"connectPanDeviceNative", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z",
|
||||
(void *)connectPanDeviceNative},
|
||||
{"disconnectPanDeviceNative", "(Ljava/lang/String;)Z", (void *)disconnectPanDeviceNative},
|
||||
};
|
||||
|
||||
|
||||
int register_android_server_BluetoothService(JNIEnv *env) {
|
||||
return AndroidRuntime::registerNativeMethods(env,
|
||||
"android/server/BluetoothService", sMethods, NELEM(sMethods));
|
||||
|
||||
@@ -121,6 +121,12 @@
|
||||
<string-array translatable="false" name="config_tether_wifi_regexs">
|
||||
</string-array>
|
||||
|
||||
<!-- List of regexpressions describing the interface (if any) that represent tetherable
|
||||
bluetooth interfaces. If the device doesn't want to support tethering over bluetooth this
|
||||
should be empty. -->
|
||||
<string-array translatable="false" name="config_tether_bluetooth_regexs">
|
||||
</string-array>
|
||||
|
||||
<!-- Dhcp range (min, max) to use for tethering purposes -->
|
||||
<string-array translatable="false" name="config_tether_dhcp_range">
|
||||
</string-array>
|
||||
|
||||
@@ -344,7 +344,8 @@ public class ConnectivityService extends IConnectivityManager.Stub {
|
||||
mTetheringConfigValid = (((mNetTrackers[ConnectivityManager.TYPE_MOBILE_DUN] != null) ||
|
||||
!mTethering.isDunRequired()) &&
|
||||
(mTethering.getTetherableUsbRegexs().length != 0 ||
|
||||
mTethering.getTetherableWifiRegexs().length != 0) &&
|
||||
mTethering.getTetherableWifiRegexs().length != 0 ||
|
||||
mTethering.getTetherableBluetoothRegexs().length != 0) &&
|
||||
mTethering.getUpstreamIfaceRegexs().length != 0);
|
||||
|
||||
}
|
||||
@@ -1676,6 +1677,15 @@ public class ConnectivityService extends IConnectivityManager.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
public String[] getTetherableBluetoothRegexs() {
|
||||
enforceTetherAccessPermission();
|
||||
if (isTetheringSupported()) {
|
||||
return mTethering.getTetherableBluetoothRegexs();
|
||||
} else {
|
||||
return new String[0];
|
||||
}
|
||||
}
|
||||
|
||||
// TODO - move iface listing, queries, etc to new module
|
||||
// javadoc from interface
|
||||
public String[] getTetherableIfaces() {
|
||||
|
||||
@@ -128,11 +128,12 @@ final class NativeDaemonConnector implements Runnable {
|
||||
Slog.e(TAG, String.format(
|
||||
"Error handling '%s'", event), ex);
|
||||
}
|
||||
}
|
||||
try {
|
||||
mResponseQueue.put(event);
|
||||
} catch (InterruptedException ex) {
|
||||
Slog.e(TAG, "Failed to put response onto queue", ex);
|
||||
} else {
|
||||
try {
|
||||
mResponseQueue.put(event);
|
||||
} catch (InterruptedException ex) {
|
||||
Slog.e(TAG, "Failed to put response onto queue", ex);
|
||||
}
|
||||
}
|
||||
} catch (NumberFormatException nfe) {
|
||||
Slog.w(TAG, String.format("Bad msg (%s)", event));
|
||||
@@ -209,6 +210,7 @@ final class NativeDaemonConnector implements Runnable {
|
||||
*/
|
||||
public synchronized ArrayList<String> doCommand(String cmd)
|
||||
throws NativeDaemonConnectorException {
|
||||
mResponseQueue.clear();
|
||||
sendCommand(cmd);
|
||||
|
||||
ArrayList<String> response = new ArrayList<String>();
|
||||
|
||||
@@ -19,8 +19,8 @@ package com.android.server.connectivity;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.bluetooth.BluetoothPan;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
@@ -32,7 +32,6 @@ import android.net.InterfaceConfiguration;
|
||||
import android.net.IConnectivityManager;
|
||||
import android.net.INetworkManagementEventObserver;
|
||||
import android.net.NetworkInfo;
|
||||
import android.net.NetworkUtils;
|
||||
import android.os.Binder;
|
||||
import android.os.Environment;
|
||||
import android.os.HandlerThread;
|
||||
@@ -53,6 +52,7 @@ import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Set;
|
||||
/**
|
||||
* @hide
|
||||
@@ -75,6 +75,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
|
||||
// TODO - remove both of these - should be part of interface inspection/selection stuff
|
||||
private String[] mTetherableUsbRegexs;
|
||||
private String[] mTetherableWifiRegexs;
|
||||
private String[] mTetherableBluetoothRegexs;
|
||||
private String[] mUpstreamIfaceRegexs;
|
||||
|
||||
private Looper mLooper;
|
||||
@@ -94,6 +95,8 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
|
||||
private static final String DHCP_DEFAULT_RANGE1_STOP = "192.168.42.254";
|
||||
private static final String DHCP_DEFAULT_RANGE2_START = "192.168.43.2";
|
||||
private static final String DHCP_DEFAULT_RANGE2_STOP = "192.168.43.254";
|
||||
private static final String DHCP_DEFAULT_RANGE3_START = "192.168.44.9";
|
||||
private static final String DHCP_DEFAULT_RANGE3_STOP = "192.168.44.254";
|
||||
|
||||
private String[] mDnsServers;
|
||||
private static final String DNS_DEFAULT_SERVER1 = "8.8.8.8";
|
||||
@@ -153,11 +156,13 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
|
||||
mDhcpRange = context.getResources().getStringArray(
|
||||
com.android.internal.R.array.config_tether_dhcp_range);
|
||||
if ((mDhcpRange.length == 0) || (mDhcpRange.length % 2 ==1)) {
|
||||
mDhcpRange = new String[4];
|
||||
mDhcpRange = new String[6];
|
||||
mDhcpRange[0] = DHCP_DEFAULT_RANGE1_START;
|
||||
mDhcpRange[1] = DHCP_DEFAULT_RANGE1_STOP;
|
||||
mDhcpRange[2] = DHCP_DEFAULT_RANGE2_START;
|
||||
mDhcpRange[3] = DHCP_DEFAULT_RANGE2_STOP;
|
||||
mDhcpRange[4] = DHCP_DEFAULT_RANGE3_START;
|
||||
mDhcpRange[5] = DHCP_DEFAULT_RANGE3_STOP;
|
||||
}
|
||||
mDunRequired = false; // resample when we turn on
|
||||
|
||||
@@ -165,6 +170,8 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
|
||||
com.android.internal.R.array.config_tether_usb_regexs);
|
||||
mTetherableWifiRegexs = context.getResources().getStringArray(
|
||||
com.android.internal.R.array.config_tether_wifi_regexs);
|
||||
mTetherableBluetoothRegexs = context.getResources().getStringArray(
|
||||
com.android.internal.R.array.config_tether_bluetooth_regexs);
|
||||
mUpstreamIfaceRegexs = context.getResources().getStringArray(
|
||||
com.android.internal.R.array.config_tether_upstream_regexs);
|
||||
|
||||
@@ -183,6 +190,8 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
|
||||
} else if (isUsb(iface)) {
|
||||
found = true;
|
||||
usb = true;
|
||||
} else if (isBluetooth(iface)) {
|
||||
found = true;
|
||||
}
|
||||
if (found == false) return;
|
||||
|
||||
@@ -217,6 +226,12 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isBluetooth(String iface) {
|
||||
for (String regex : mTetherableBluetoothRegexs) {
|
||||
if (iface.matches(regex)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public void interfaceAdded(String iface) {
|
||||
IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
|
||||
INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
|
||||
@@ -229,6 +244,9 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
|
||||
found = true;
|
||||
usb = true;
|
||||
}
|
||||
if (isBluetooth(iface)) {
|
||||
found = true;
|
||||
}
|
||||
if (found == false) {
|
||||
if (DEBUG) Log.d(TAG, iface + " is not a tetherable iface, ignoring");
|
||||
return;
|
||||
@@ -324,13 +342,14 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
|
||||
|
||||
boolean wifiTethered = false;
|
||||
boolean usbTethered = false;
|
||||
boolean bluetoothTethered = false;
|
||||
|
||||
synchronized (mIfaces) {
|
||||
Set ifaces = mIfaces.keySet();
|
||||
for (Object iface : ifaces) {
|
||||
TetherInterfaceSM sm = mIfaces.get(iface);
|
||||
if (sm != null) {
|
||||
if(sm.isErrored()) {
|
||||
if (sm.isErrored()) {
|
||||
erroredList.add((String)iface);
|
||||
} else if (sm.isAvailable()) {
|
||||
availableList.add((String)iface);
|
||||
@@ -339,6 +358,8 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
|
||||
usbTethered = true;
|
||||
} else if (isWifi((String)iface)) {
|
||||
wifiTethered = true;
|
||||
} else if (isBluetooth((String)iface)) {
|
||||
bluetoothTethered = true;
|
||||
}
|
||||
activeList.add((String)iface);
|
||||
}
|
||||
@@ -359,13 +380,19 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
|
||||
}
|
||||
|
||||
if (usbTethered) {
|
||||
if (wifiTethered) {
|
||||
if (wifiTethered || bluetoothTethered) {
|
||||
showTetheredNotification(com.android.internal.R.drawable.stat_sys_tether_general);
|
||||
} else {
|
||||
showTetheredNotification(com.android.internal.R.drawable.stat_sys_tether_usb);
|
||||
}
|
||||
} else if (wifiTethered) {
|
||||
showTetheredNotification(com.android.internal.R.drawable.stat_sys_tether_wifi);
|
||||
if (bluetoothTethered) {
|
||||
showTetheredNotification(com.android.internal.R.drawable.stat_sys_tether_general);
|
||||
} else {
|
||||
showTetheredNotification(com.android.internal.R.drawable.stat_sys_tether_wifi);
|
||||
}
|
||||
} else if (bluetoothTethered) {
|
||||
showTetheredNotification(com.android.internal.R.drawable.stat_sys_tether_bluetooth);
|
||||
} else {
|
||||
clearTetheredNotification();
|
||||
}
|
||||
@@ -396,7 +423,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
|
||||
CharSequence message = r.getText(com.android.internal.R.string.
|
||||
tethered_notification_message);
|
||||
|
||||
if(mTetheredNotification == null) {
|
||||
if (mTetheredNotification == null) {
|
||||
mTetheredNotification = new Notification();
|
||||
mTetheredNotification.when = 0;
|
||||
}
|
||||
@@ -471,7 +498,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
// toggled when we enter/leave the fully teathered state
|
||||
// toggled when we enter/leave the fully tethered state
|
||||
private boolean enableUsbRndis(boolean enabled) {
|
||||
if (DEBUG) Log.d(TAG, "enableUsbRndis(" + enabled + ")");
|
||||
IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
|
||||
@@ -554,6 +581,10 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
|
||||
return mTetherableWifiRegexs;
|
||||
}
|
||||
|
||||
public String[] getTetherableBluetoothRegexs() {
|
||||
return mTetherableBluetoothRegexs;
|
||||
}
|
||||
|
||||
public String[] getUpstreamIfaceRegexs() {
|
||||
return mUpstreamIfaceRegexs;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user