Non persistent adapter service
Change-Id: Ib13d5c77416e58161df0e04d7a15ec0dddbde8b5
Conflicts:
core/java/android/bluetooth/BluetoothInputDevice.java
Conflicts:
core/java/com/android/internal/app/ShutdownThread.java
services/java/com/android/server/SystemServer.java
Conflicts:
services/java/com/android/server/SystemServer.java
services/java/com/android/server/pm/ShutdownThread.java
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index c59a5aa..bf5f175 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -108,6 +108,36 @@
private IBluetoothA2dp mService;
private BluetoothAdapter mAdapter;
+ final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
+ new IBluetoothStateChangeCallback.Stub() {
+ public void onBluetoothStateChange(boolean up) {
+ if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
+ if (!up) {
+ if (DBG) Log.d(TAG,"Unbinding service...");
+ synchronized (mConnection) {
+ try {
+ mService = null;
+ mContext.unbindService(mConnection);
+ } catch (Exception re) {
+ Log.e(TAG,"",re);
+ }
+ }
+ } else {
+ synchronized (mConnection) {
+ try {
+ if (mService == null) {
+ if (DBG) Log.d(TAG,"Binding service...");
+ if (!mContext.bindService(new Intent(IBluetoothA2dp.class.getName()), mConnection, 0)) {
+ Log.e(TAG, "Could not bind to Bluetooth A2DP Service");
+ }
+ }
+ } catch (Exception re) {
+ Log.e(TAG,"",re);
+ }
+ }
+ }
+ }
+ };
/**
* Create a BluetoothA2dp proxy object for interacting with the local
* Bluetooth A2DP service.
@@ -117,6 +147,15 @@
mContext = context;
mServiceListener = l;
mAdapter = BluetoothAdapter.getDefaultAdapter();
+ IBluetoothManager mgr = mAdapter.getBluetoothManager();
+ if (mgr != null) {
+ try {
+ mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
+ } catch (RemoteException e) {
+ Log.e(TAG,"",e);
+ }
+ }
+
if (!context.bindService(new Intent(IBluetoothA2dp.class.getName()), mConnection, 0)) {
Log.e(TAG, "Could not bind to Bluetooth A2DP Service");
}
@@ -124,8 +163,30 @@
/*package*/ void close() {
mServiceListener = null;
+ IBluetoothManager mgr = mAdapter.getBluetoothManager();
+ if (mgr != null) {
+ try {
+ mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
+ } catch (Exception e) {
+ Log.e(TAG,"",e);
+ }
+ }
+
+ synchronized (mConnection) {
+ if (mService != null) {
+ try {
+ mService = null;
+ mContext.unbindService(mConnection);
+ } catch (Exception re) {
+ Log.e(TAG,"",re);
+ }
+ }
+ }
}
+ public void finalize() {
+ close();
+ }
/**
* Initiate connection to a profile of the remote bluetooth device.
*
@@ -260,7 +321,7 @@
* Set priority of the profile
*
* <p> The device should already be paired.
- * Priority can be one of {@link #PRIORITY_ON} or
+ * Priority can be one of {@link #PRIORITY_ON} orgetBluetoothManager
* {@link #PRIORITY_OFF},
*
* <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index c822754..75ef3dd 100755
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -73,7 +73,7 @@
*/
public final class BluetoothAdapter {
private static final String TAG = "BluetoothAdapter";
- private static final boolean DBG = false;
+ private static final boolean DBG = true;
/**
* Sentinel error value for this class. Guaranteed to not equal any other
@@ -343,7 +343,7 @@
public static final int STATE_DISCONNECTING = 3;
/** @hide */
- public static final String BLUETOOTH_SERVICE = "bluetooth";
+ public static final String BLUETOOTH_MANAGER_SERVICE = "bluetooth_manager";
private static final int ADDRESS_LENGTH = 17;
@@ -353,7 +353,8 @@
*/
private static BluetoothAdapter sAdapter;
- private final IBluetooth mService;
+ private final IBluetoothManager mManagerService;
+ private IBluetooth mService;
private Handler mServiceRecordHandler;
@@ -367,10 +368,10 @@
*/
public static synchronized BluetoothAdapter getDefaultAdapter() {
if (sAdapter == null) {
- IBinder b = ServiceManager.getService("bluetooth");
+ IBinder b = ServiceManager.getService(BLUETOOTH_MANAGER_SERVICE);
if (b != null) {
- IBluetooth service = IBluetooth.Stub.asInterface(b);
- sAdapter = new BluetoothAdapter(service);
+ IBluetoothManager managerService = IBluetoothManager.Stub.asInterface(b);
+ sAdapter = new BluetoothAdapter(managerService);
} else {
Log.e(TAG, "Bluetooth binder is null");
}
@@ -381,11 +382,15 @@
/**
* Use {@link #getDefaultAdapter} to get the BluetoothAdapter instance.
*/
- BluetoothAdapter(IBluetooth service) {
- if (service == null) {
- throw new IllegalArgumentException("service is null");
+ BluetoothAdapter(IBluetoothManager managerService) {
+
+ if (managerService == null) {
+ throw new IllegalArgumentException("bluetooth manager service is null");
}
- mService = service;
+ try {
+ mService = managerService.registerAdapter(mManagerCallback);
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
+ mManagerService = managerService;
mServiceRecordHandler = null;
}
@@ -402,6 +407,10 @@
* @throws IllegalArgumentException if address is invalid
*/
public BluetoothDevice getRemoteDevice(String address) {
+ if (mService == null) {
+ Log.e(TAG, "BT not enabled. Cannot create Remote Device");
+ return null;
+ }
return new BluetoothDevice(address);
}
@@ -433,8 +442,11 @@
* @return true if the local adapter is turned on
*/
public boolean isEnabled() {
+
try {
- return mService.isEnabled();
+ synchronized(mManagerCallback) {
+ if (mService != null) return mService.isEnabled();
+ }
} catch (RemoteException e) {Log.e(TAG, "", e);}
return false;
}
@@ -451,9 +463,15 @@
* @return current state of Bluetooth adapter
*/
public int getState() {
- if (mService == null) return STATE_OFF;
try {
- return mService.getState();
+ synchronized(mManagerCallback) {
+ if (mService != null)
+ {
+ return mService.getState();
+ }
+ // TODO(BT) there might be a small gap during STATE_TURNING_ON that
+ // mService is null, handle that case
+ }
} catch (RemoteException e) {Log.e(TAG, "", e);}
return STATE_OFF;
}
@@ -486,8 +504,13 @@
* immediate error
*/
public boolean enable() {
+
+ boolean enabled = false;
try {
- return mService.enable();
+ enabled = mManagerService.enable();
+ if (enabled) {
+ // TODO(BT)
+ }
} catch (RemoteException e) {Log.e(TAG, "", e);}
return false;
}
@@ -518,7 +541,7 @@
*/
public boolean disable() {
try {
- return mService.disable(true);
+ return mManagerService.disable(true);
} catch (RemoteException e) {Log.e(TAG, "", e);}
return false;
}
@@ -534,8 +557,9 @@
* @hide
*/
public boolean disable(boolean persist) {
+
try {
- return mService.disable(persist);
+ return mManagerService.disable(persist);
} catch (RemoteException e) {Log.e(TAG, "", e);}
return false;
}
@@ -549,7 +573,7 @@
*/
public String getAddress() {
try {
- return mService.getAddress();
+ return mManagerService.getAddress();
} catch (RemoteException e) {Log.e(TAG, "", e);}
return null;
}
@@ -563,7 +587,7 @@
*/
public String getName() {
try {
- return mService.getName();
+ return mManagerService.getName();
} catch (RemoteException e) {Log.e(TAG, "", e);}
return null;
}
@@ -579,7 +603,9 @@
public ParcelUuid[] getUuids() {
if (getState() != STATE_ON) return null;
try {
- return mService.getUuids();
+ synchronized(mManagerCallback) {
+ if (mService != null) return mService.getUuids();
+ }
} catch (RemoteException e) {Log.e(TAG, "", e);}
return null;
}
@@ -602,7 +628,9 @@
public boolean setName(String name) {
if (getState() != STATE_ON) return false;
try {
- return mService.setName(name);
+ synchronized(mManagerCallback) {
+ if (mService != null) return mService.setName(name);
+ }
} catch (RemoteException e) {Log.e(TAG, "", e);}
return false;
}
@@ -626,7 +654,9 @@
public int getScanMode() {
if (getState() != STATE_ON) return SCAN_MODE_NONE;
try {
- return mService.getScanMode();
+ synchronized(mManagerCallback) {
+ if (mService != null) return mService.getScanMode();
+ }
} catch (RemoteException e) {Log.e(TAG, "", e);}
return SCAN_MODE_NONE;
}
@@ -662,7 +692,9 @@
public boolean setScanMode(int mode, int duration) {
if (getState() != STATE_ON) return false;
try {
- return mService.setScanMode(mode, duration);
+ synchronized(mManagerCallback) {
+ if (mService != null) return mService.setScanMode(mode, duration);
+ }
} catch (RemoteException e) {Log.e(TAG, "", e);}
return false;
}
@@ -678,7 +710,9 @@
public int getDiscoverableTimeout() {
if (getState() != STATE_ON) return -1;
try {
- return mService.getDiscoverableTimeout();
+ synchronized(mManagerCallback) {
+ if (mService != null) return mService.getDiscoverableTimeout();
+ }
} catch (RemoteException e) {Log.e(TAG, "", e);}
return -1;
}
@@ -687,7 +721,9 @@
public void setDiscoverableTimeout(int timeout) {
if (getState() != STATE_ON) return;
try {
- mService.setDiscoverableTimeout(timeout);
+ synchronized(mManagerCallback) {
+ if (mService != null) mService.setDiscoverableTimeout(timeout);
+ }
} catch (RemoteException e) {Log.e(TAG, "", e);}
}
@@ -724,7 +760,9 @@
public boolean startDiscovery() {
if (getState() != STATE_ON) return false;
try {
- return mService.startDiscovery();
+ synchronized(mManagerCallback) {
+ if (mService != null) return mService.startDiscovery();
+ }
} catch (RemoteException e) {Log.e(TAG, "", e);}
return false;
}
@@ -749,7 +787,9 @@
public boolean cancelDiscovery() {
if (getState() != STATE_ON) return false;
try {
- return mService.cancelDiscovery();
+ synchronized(mManagerCallback) {
+ if (mService != null) return mService.cancelDiscovery();
+ }
} catch (RemoteException e) {Log.e(TAG, "", e);}
return false;
}
@@ -776,7 +816,9 @@
public boolean isDiscovering() {
if (getState() != STATE_ON) return false;
try {
- return mService.isDiscovering();
+ synchronized(mManagerCallback) {
+ if (mService != null ) return mService.isDiscovering();
+ }
} catch (RemoteException e) {Log.e(TAG, "", e);}
return false;
}
@@ -797,7 +839,10 @@
return toDeviceSet(new BluetoothDevice[0]);
}
try {
- return toDeviceSet(mService.getBondedDevices());
+ synchronized(mManagerCallback) {
+ if (mService != null) return toDeviceSet(mService.getBondedDevices());
+ }
+ return toDeviceSet(new BluetoothDevice[0]);
} catch (RemoteException e) {Log.e(TAG, "", e);}
return null;
}
@@ -818,7 +863,9 @@
public int getConnectionState() {
if (getState() != STATE_ON) return BluetoothAdapter.STATE_DISCONNECTED;
try {
- return mService.getAdapterConnectionState();
+ synchronized(mManagerCallback) {
+ if (mService != null) return mService.getAdapterConnectionState();
+ }
} catch (RemoteException e) {Log.e(TAG, "getConnectionState:", e);}
return BluetoothAdapter.STATE_DISCONNECTED;
}
@@ -841,7 +888,9 @@
public int getProfileConnectionState(int profile) {
if (getState() != STATE_ON) return BluetoothProfile.STATE_DISCONNECTED;
try {
- return mService.getProfileConnectionState(profile);
+ synchronized(mManagerCallback) {
+ if (mService != null) return mService.getProfileConnectionState(profile);
+ }
} catch (RemoteException e) {
Log.e(TAG, "getProfileConnectionState:", e);
}
@@ -1160,6 +1209,23 @@
}
}
+ final private IBluetoothManagerCallback mManagerCallback =
+ new IBluetoothManagerCallback.Stub() {
+ public void onBluetoothServiceUp(IBluetooth bluetoothService) {
+ if (DBG) Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService);
+ synchronized (mManagerCallback) {
+ mService = bluetoothService;
+ }
+ }
+
+ public void onBluetoothServiceDown() {
+ if (DBG) Log.d(TAG, "onBluetoothServiceDown: " + mService);
+ synchronized (mManagerCallback) {
+ mService = null;
+ }
+ }
+ };
+
/**
* Enable the Bluetooth Adapter, but don't auto-connect devices
* and don't persist state. Only for use by system applications.
@@ -1245,6 +1311,17 @@
return Collections.unmodifiableSet(deviceSet);
}
+ protected void finalize() throws Throwable {
+ try {
+ mManagerService.unregisterAdapter(mManagerCallback);
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ } finally {
+ super.finalize();
+ }
+ }
+
+
/**
* Validate a String Bluetooth address, such as "00:43:A8:23:10:F0"
* <p>Alphabetic characters must be uppercase to be valid.
@@ -1275,4 +1352,14 @@
}
return true;
}
+
+ /*package*/ IBluetoothManager getBluetoothManager() {
+ return mManagerService;
+ }
+
+ /*package*/ IBluetooth getBluetoothService() {
+ synchronized (mManagerCallback) {
+ return mService;
+ }
+ }
}
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 4d9dd82..82bd702 100755
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -65,6 +65,7 @@
*/
public final class BluetoothDevice implements Parcelable {
private static final String TAG = "BluetoothDevice";
+ private static final boolean DBG = true;
/**
* Sentinel error value for this class. Guaranteed to not equal any other
@@ -483,11 +484,8 @@
/*package*/ static IBluetooth getService() {
synchronized (BluetoothDevice.class) {
if (sService == null) {
- IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_SERVICE);
- if (b == null) {
- throw new RuntimeException("Bluetooth service not available");
- }
- sService = IBluetooth.Stub.asInterface(b);
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ sService = adapter.getBluetoothService();
}
}
return sService;
@@ -561,6 +559,7 @@
* @return Bluetooth hardware address as string
*/
public String getAddress() {
+ if (DBG) Log.d(TAG, "mAddress: " + mAddress);
return mAddress;
}
@@ -575,6 +574,10 @@
* @return the Bluetooth name, or null if there was a problem.
*/
public String getName() {
+ if (sService == null) {
+ Log.e(TAG, "BT not enabled. Cannot get Remote Device name");
+ return null;
+ }
try {
return sService.getRemoteName(this);
} catch (RemoteException e) {Log.e(TAG, "", e);}
@@ -589,6 +592,10 @@
* @hide
*/
public String getAlias() {
+ if (sService == null) {
+ Log.e(TAG, "BT not enabled. Cannot get Remote Device Alias");
+ return null;
+ }
try {
return sService.getRemoteAlias(this);
} catch (RemoteException e) {Log.e(TAG, "", e);}
@@ -606,6 +613,10 @@
* @hide
*/
public boolean setAlias(String alias) {
+ if (sService == null) {
+ Log.e(TAG, "BT not enabled. Cannot set Remote Device name");
+ return false;
+ }
try {
return sService.setRemoteAlias(this, alias);
} catch (RemoteException e) {Log.e(TAG, "", e);}
@@ -642,6 +653,10 @@
* @hide
*/
public boolean createBond() {
+ if (sService == null) {
+ Log.e(TAG, "BT not enabled. Cannot create bond to Remote Device");
+ return false;
+ }
try {
return sService.createBond(this);
} catch (RemoteException e) {Log.e(TAG, "", e);}
@@ -706,6 +721,10 @@
* @hide
*/
public boolean cancelBondProcess() {
+ if (sService == null) {
+ Log.e(TAG, "BT not enabled. Cannot cancel Remote Device bond");
+ return false;
+ }
try {
return sService.cancelBondProcess(this);
} catch (RemoteException e) {Log.e(TAG, "", e);}
@@ -723,6 +742,10 @@
* @hide
*/
public boolean removeBond() {
+ if (sService == null) {
+ Log.e(TAG, "BT not enabled. Cannot remove Remote Device bond");
+ return false;
+ }
try {
return sService.removeBond(this);
} catch (RemoteException e) {Log.e(TAG, "", e);}
@@ -740,6 +763,10 @@
* @return the bond state
*/
public int getBondState() {
+ if (sService == null) {
+ Log.e(TAG, "BT not enabled. Cannot get bond state");
+ return BOND_NONE;
+ }
try {
return sService.getBondState(this);
} catch (RemoteException e) {Log.e(TAG, "", e);}
@@ -753,6 +780,10 @@
* @return Bluetooth class object, or null on error
*/
public BluetoothClass getBluetoothClass() {
+ if (sService == null) {
+ Log.e(TAG, "BT not enabled. Cannot get Bluetooth Class");
+ return null;
+ }
try {
int classInt = sService.getRemoteClass(this);
if (classInt == BluetoothClass.ERROR) return null;
@@ -807,6 +838,10 @@
* or null on error
*/
public ParcelUuid[] getUuids() {
+ if (sService == null) {
+ Log.e(TAG, "BT not enabled. Cannot get remote device Uuids");
+ return null;
+ }
try {
return sService.getRemoteUuids(this);
} catch (RemoteException e) {Log.e(TAG, "", e);}
@@ -847,6 +882,10 @@
/** @hide */
public boolean setPin(byte[] pin) {
+ if (sService == null) {
+ Log.e(TAG, "BT not enabled. Cannot set Remote Device pin");
+ return false;
+ }
try {
return sService.setPin(this, true, pin.length, pin);
} catch (RemoteException e) {Log.e(TAG, "", e);}
@@ -865,6 +904,10 @@
/** @hide */
public boolean setPairingConfirmation(boolean confirm) {
+ if (sService == null) {
+ Log.e(TAG, "BT not enabled. Cannot set pairing confirmation");
+ return false;
+ }
try {
return sService.setPairingConfirmation(this, confirm);
} catch (RemoteException e) {Log.e(TAG, "", e);}
@@ -883,6 +926,10 @@
/** @hide */
public boolean cancelPairingUserInput() {
+ if (sService == null) {
+ Log.e(TAG, "BT not enabled. Cannot create pairing user input");
+ return false;
+ }
try {
return sService.cancelBondProcess(this);
} catch (RemoteException e) {Log.e(TAG, "", e);}
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index 2df33a63..541b69f 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -45,7 +45,7 @@
*/
public final class BluetoothHeadset implements BluetoothProfile {
private static final String TAG = "BluetoothHeadset";
- private static final boolean DBG = false;
+ private static final boolean DBG = true;
/**
* Intent used to broadcast the change in connection state of the Headset
@@ -221,6 +221,37 @@
private IBluetoothHeadset mService;
private BluetoothAdapter mAdapter;
+ final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
+ new IBluetoothStateChangeCallback.Stub() {
+ public void onBluetoothStateChange(boolean up) {
+ if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
+ if (!up) {
+ if (DBG) Log.d(TAG,"Unbinding service...");
+ synchronized (mConnection) {
+ try {
+ mService = null;
+ mContext.unbindService(mConnection);
+ } catch (Exception re) {
+ Log.e(TAG,"",re);
+ }
+ }
+ } else {
+ synchronized (mConnection) {
+ try {
+ if (mService == null) {
+ if (DBG) Log.d(TAG,"Binding service...");
+ if (!mContext.bindService(new Intent(IBluetoothHeadset.class.getName()), mConnection, 0)) {
+ Log.e(TAG, "Could not bind to Bluetooth Headset Service");
+ }
+ }
+ } catch (Exception re) {
+ Log.e(TAG,"",re);
+ }
+ }
+ }
+ }
+ };
+
/**
* Create a BluetoothHeadset proxy object.
*/
@@ -228,6 +259,16 @@
mContext = context;
mServiceListener = l;
mAdapter = BluetoothAdapter.getDefaultAdapter();
+
+ IBluetoothManager mgr = mAdapter.getBluetoothManager();
+ if (mgr != null) {
+ try {
+ mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
+ } catch (RemoteException e) {
+ Log.e(TAG,"",e);
+ }
+ }
+
if (!context.bindService(new Intent(IBluetoothHeadset.class.getName()), mConnection, 0)) {
Log.e(TAG, "Could not bind to Bluetooth Headset Service");
}
@@ -241,9 +282,25 @@
*/
/*package*/ void close() {
if (DBG) log("close()");
- if (mConnection != null) {
- mContext.unbindService(mConnection);
- mConnection = null;
+
+ IBluetoothManager mgr = mAdapter.getBluetoothManager();
+ if (mgr != null) {
+ try {
+ mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
+ } catch (Exception e) {
+ Log.e(TAG,"",e);
+ }
+ }
+
+ synchronized (mConnection) {
+ if (mService != null) {
+ try {
+ mService = null;
+ mContext.unbindService(mConnection);
+ } catch (Exception re) {
+ Log.e(TAG,"",re);
+ }
+ }
}
mServiceListener = null;
}
diff --git a/core/java/android/bluetooth/BluetoothHealth.java b/core/java/android/bluetooth/BluetoothHealth.java
index 5dad291..4a0bc7e 100644
--- a/core/java/android/bluetooth/BluetoothHealth.java
+++ b/core/java/android/bluetooth/BluetoothHealth.java
@@ -57,7 +57,7 @@
*/
public final class BluetoothHealth implements BluetoothProfile {
private static final String TAG = "BluetoothHealth";
- private static final boolean DBG = false;
+ private static final boolean DBG = true;
/**
* Health Profile Source Role - the health device.
@@ -97,6 +97,37 @@
/** @hide */
public static final int HEALTH_OPERATION_NOT_ALLOWED = 6005;
+ final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
+ new IBluetoothStateChangeCallback.Stub() {
+ public void onBluetoothStateChange(boolean up) {
+ if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
+ if (!up) {
+ if (DBG) Log.d(TAG,"Unbinding service...");
+ synchronized (mConnection) {
+ try {
+ mService = null;
+ mContext.unbindService(mConnection);
+ } catch (Exception re) {
+ Log.e(TAG,"",re);
+ }
+ }
+ } else {
+ synchronized (mConnection) {
+ try {
+ if (mService == null) {
+ if (DBG) Log.d(TAG,"Binding service...");
+ if (!mContext.bindService(new Intent(IBluetoothHealth.class.getName()), mConnection, 0)) {
+ Log.e(TAG, "Could not bind to Bluetooth Health Service");
+ }
+ }
+ } catch (Exception re) {
+ Log.e(TAG,"",re);
+ }
+ }
+ }
+ }
+ };
+
/**
* Register an application configuration that acts as a Health SINK.
@@ -442,6 +473,15 @@
mContext = context;
mServiceListener = l;
mAdapter = BluetoothAdapter.getDefaultAdapter();
+ IBluetoothManager mgr = mAdapter.getBluetoothManager();
+ if (mgr != null) {
+ try {
+ mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
+ } catch (RemoteException e) {
+ Log.e(TAG,"",e);
+ }
+ }
+
if (!context.bindService(new Intent(IBluetoothHealth.class.getName()), mConnection, 0)) {
Log.e(TAG, "Could not bind to Bluetooth Health Service");
}
@@ -449,9 +489,24 @@
/*package*/ void close() {
if (DBG) log("close()");
- if (mConnection != null) {
- mContext.unbindService(mConnection);
- mConnection = null;
+ IBluetoothManager mgr = mAdapter.getBluetoothManager();
+ if (mgr != null) {
+ try {
+ mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
+ } catch (Exception e) {
+ Log.e(TAG,"",e);
+ }
+ }
+
+ synchronized (mConnection) {
+ if (mService != null) {
+ try {
+ mService = null;
+ mContext.unbindService(mConnection);
+ } catch (Exception re) {
+ Log.e(TAG,"",re);
+ }
+ }
}
mServiceListener = null;
}
diff --git a/core/java/android/bluetooth/BluetoothInputDevice.java b/core/java/android/bluetooth/BluetoothInputDevice.java
index 478a9d3..bff966d 100755
--- a/core/java/android/bluetooth/BluetoothInputDevice.java
+++ b/core/java/android/bluetooth/BluetoothInputDevice.java
@@ -44,7 +44,7 @@
*/
public final class BluetoothInputDevice implements BluetoothProfile {
private static final String TAG = "BluetoothInputDevice";
- private static final boolean DBG = false;
+ private static final boolean DBG = true;
/**
* Intent used to broadcast the change in connection state of the Input
@@ -186,6 +186,37 @@
private BluetoothAdapter mAdapter;
private IBluetoothInputDevice mService;
+ final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
+ new IBluetoothStateChangeCallback.Stub() {
+ public void onBluetoothStateChange(boolean up) {
+ if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
+ if (!up) {
+ if (DBG) Log.d(TAG,"Unbinding service...");
+ synchronized (mConnection) {
+ try {
+ mService = null;
+ mContext.unbindService(mConnection);
+ } catch (Exception re) {
+ Log.e(TAG,"",re);
+ }
+ }
+ } else {
+ synchronized (mConnection) {
+ try {
+ if (mService == null) {
+ if (DBG) Log.d(TAG,"Binding service...");
+ if (!mContext.bindService(new Intent(IBluetoothInputDevice.class.getName()), mConnection, 0)) {
+ Log.e(TAG, "Could not bind to Bluetooth HID Service");
+ }
+ }
+ } catch (Exception re) {
+ Log.e(TAG,"",re);
+ }
+ }
+ }
+ }
+ };
+
/**
* Create a BluetoothInputDevice proxy object for interacting with the local
* Bluetooth Service which handles the InputDevice profile
@@ -195,6 +226,16 @@
mContext = context;
mServiceListener = l;
mAdapter = BluetoothAdapter.getDefaultAdapter();
+
+ IBluetoothManager mgr = mAdapter.getBluetoothManager();
+ if (mgr != null) {
+ try {
+ mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
+ } catch (RemoteException e) {
+ Log.e(TAG,"",e);
+ }
+ }
+
if (!context.bindService(new Intent(IBluetoothInputDevice.class.getName()),
mConnection, 0)) {
Log.e(TAG, "Could not bind to Bluetooth HID Service");
@@ -203,9 +244,24 @@
/*package*/ void close() {
if (DBG) log("close()");
- if (mConnection != null) {
- mContext.unbindService(mConnection);
- mConnection = null;
+ IBluetoothManager mgr = mAdapter.getBluetoothManager();
+ if (mgr != null) {
+ try {
+ mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
+ } catch (Exception e) {
+ Log.e(TAG,"",e);
+ }
+ }
+
+ synchronized (mConnection) {
+ if (mService != null) {
+ try {
+ mService = null;
+ mContext.unbindService(mConnection);
+ } catch (Exception re) {
+ Log.e(TAG,"",re);
+ }
+ }
}
mServiceListener = null;
}
diff --git a/core/java/android/bluetooth/BluetoothPan.java b/core/java/android/bluetooth/BluetoothPan.java
index 13526e8..13d9078 100644
--- a/core/java/android/bluetooth/BluetoothPan.java
+++ b/core/java/android/bluetooth/BluetoothPan.java
@@ -18,7 +18,10 @@
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -27,7 +30,6 @@
import java.util.ArrayList;
import java.util.List;
-
/**
* This class provides the APIs to control the Bluetooth Pan
* Profile.
@@ -41,7 +43,7 @@
*/
public final class BluetoothPan implements BluetoothProfile {
private static final String TAG = "BluetoothPan";
- private static final boolean DBG = false;
+ private static final boolean DBG = true;
/**
* Intent used to broadcast the change in connection state of the Pan
@@ -76,15 +78,18 @@
*/
public static final String EXTRA_LOCAL_ROLE = "android.bluetooth.pan.extra.LOCAL_ROLE";
+ public static final int PAN_ROLE_NONE = 0;
/**
* The local device is acting as a Network Access Point.
*/
public static final int LOCAL_NAP_ROLE = 1;
+ public static final int REMOTE_NAP_ROLE = 1;
/**
* The local device is acting as a PAN User.
*/
public static final int LOCAL_PANU_ROLE = 2;
+ public static final int REMOTE_PANU_ROLE = 2;
/**
* Return codes for the connect and disconnect Bluez / Dbus calls.
@@ -112,34 +117,34 @@
*/
public static final int PAN_OPERATION_SUCCESS = 1004;
+ private Context mContext;
private ServiceListener mServiceListener;
private BluetoothAdapter mAdapter;
- private IBluetooth mService;
+ private IBluetoothPan mPanService;
/**
* Create a BluetoothPan proxy object for interacting with the local
* Bluetooth Service which handles the Pan profile
*
*/
- /*package*/ BluetoothPan(Context mContext, ServiceListener l) {
- IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_SERVICE);
+ /*package*/ BluetoothPan(Context context, ServiceListener l) {
+ mContext = context;
mServiceListener = l;
mAdapter = BluetoothAdapter.getDefaultAdapter();
- if (b != null) {
- mService = IBluetooth.Stub.asInterface(b);
- if (mServiceListener != null) {
- mServiceListener.onServiceConnected(BluetoothProfile.PAN, this);
- }
- } 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;
+ Log.d(TAG, "BluetoothPan() call bindService");
+ if (!context.bindService(new Intent(IBluetoothPan.class.getName()),
+ mConnection, 0)) {
+ Log.e(TAG, "Could not bind to Bluetooth HID Service");
}
+ Log.d(TAG, "BluetoothPan(), bindService called");
}
/*package*/ void close() {
+ if (DBG) log("close()");
+ if (mConnection != null) {
+ mContext.unbindService(mConnection);
+ mConnection = null;
+ }
mServiceListener = null;
}
@@ -163,18 +168,16 @@
*/
public boolean connect(BluetoothDevice device) {
if (DBG) log("connect(" + device + ")");
- if (mService != null && isEnabled() &&
+ if (mPanService != null && isEnabled() &&
isValidDevice(device)) {
- //TODO(BT
- /*
try {
- return mService.connectPanDevice(device);
+ return mPanService.connect(device);
} catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return false;
- }*/
+ }
}
- if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ if (mPanService == null) Log.w(TAG, "Proxy not attached to service");
return false;
}
@@ -206,18 +209,16 @@
*/
public boolean disconnect(BluetoothDevice device) {
if (DBG) log("disconnect(" + device + ")");
- if (mService != null && isEnabled() &&
+ if (mPanService != null && isEnabled() &&
isValidDevice(device)) {
- //TODO(BT
- /*
try {
- return mService.disconnectPanDevice(device);
+ return mPanService.disconnect(device);
} catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return false;
- }*/
+ }
}
- if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ if (mPanService == null) Log.w(TAG, "Proxy not attached to service");
return false;
}
@@ -226,17 +227,15 @@
*/
public List<BluetoothDevice> getConnectedDevices() {
if (DBG) log("getConnectedDevices()");
- if (mService != null && isEnabled()) {
- //TODO(BT
- /*
+ if (mPanService != null && isEnabled()) {
try {
- return mService.getConnectedPanDevices();
+ return mPanService.getConnectedDevices();
} catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return new ArrayList<BluetoothDevice>();
- }*/
+ }
}
- if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ if (mPanService == null) Log.w(TAG, "Proxy not attached to service");
return new ArrayList<BluetoothDevice>();
}
@@ -245,17 +244,15 @@
*/
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
if (DBG) log("getDevicesMatchingStates()");
- if (mService != null && isEnabled()) {
- //TODO(BT
- /*
+ if (mPanService != null && isEnabled()) {
try {
- return mService.getPanDevicesMatchingConnectionStates(states);
+ return mPanService.getDevicesMatchingConnectionStates(states);
} catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return new ArrayList<BluetoothDevice>();
- }*/
+ }
}
- if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ if (mPanService == null) Log.w(TAG, "Proxy not attached to service");
return new ArrayList<BluetoothDevice>();
}
@@ -264,45 +261,57 @@
*/
public int getConnectionState(BluetoothDevice device) {
if (DBG) log("getState(" + device + ")");
- if (mService != null && isEnabled()
+ if (mPanService != null && isEnabled()
&& isValidDevice(device)) {
- //TODO(BT
- /*
try {
- return mService.getPanDeviceConnectionState(device);
+ return mPanService.getConnectionState(device);
} catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
return BluetoothProfile.STATE_DISCONNECTED;
- }*/
+ }
}
- if (mService == null) Log.w(TAG, "Proxy not attached to service");
+ if (mPanService == null) Log.w(TAG, "Proxy not attached to service");
return BluetoothProfile.STATE_DISCONNECTED;
}
public void setBluetoothTethering(boolean value) {
if (DBG) log("setBluetoothTethering(" + value + ")");
- //TODO(BT
- /*
try {
- mService.setBluetoothTethering(value);
+ mPanService.setBluetoothTethering(value);
} catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
- }*/
+ }
}
public boolean isTetheringOn() {
if (DBG) log("isTetheringOn()");
- //TODO(BT
- /*
try {
- return mService.isTetheringOn();
+ return mPanService.isTetheringOn();
} catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
- return false;
- }*/
+ }
return false;
}
+ private ServiceConnection mConnection = new ServiceConnection() {
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ if (DBG) Log.d(TAG, "BluetoothPAN Proxy object connected");
+ mPanService = IBluetoothPan.Stub.asInterface(service);
+
+ if (mServiceListener != null) {
+ mServiceListener.onServiceConnected(BluetoothProfile.PAN,
+ BluetoothPan.this);
+ }
+ }
+ public void onServiceDisconnected(ComponentName className) {
+ if (DBG) Log.d(TAG, "BluetoothPAN Proxy object disconnected");
+ mPanService = null;
+ if (mServiceListener != null) {
+ mServiceListener.onServiceDisconnected(BluetoothProfile.PAN);
+ }
+ }
+ };
+
private boolean isEnabled() {
if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true;
return false;
diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java
index 9b0e1cb..d37f2d5 100644
--- a/core/java/android/bluetooth/BluetoothSocket.java
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -102,7 +102,6 @@
private int mPort; /* RFCOMM channel or L2CAP psm */
private int mFd;
private String mServiceName;
- private static IBluetooth sBluetoothProxy;
private static int PROXY_CONNECTION_TIMEOUT = 5000;
private static int SOCK_SIGNAL_SIZE = 16;
@@ -158,17 +157,6 @@
}
mInputStream = new BluetoothInputStream(this);
mOutputStream = new BluetoothOutputStream(this);
-
- if (sBluetoothProxy == null) {
- synchronized (BluetoothSocket.class) {
- if (sBluetoothProxy == null) {
- IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_SERVICE);
- if (b == null)
- throw new RuntimeException("Bluetooth service not available");
- sBluetoothProxy = IBluetooth.Stub.asInterface(b);
- }
- }
- }
}
private BluetoothSocket(BluetoothSocket s) {
mUuid = s.mUuid;
@@ -297,8 +285,9 @@
try {
// TODO(BT) derive flag from auth and encrypt
if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed");
-
- mPfd = sBluetoothProxy.connectSocket(mDevice, mType,
+ IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService();
+ if (bluetoothProxy == null) throw new IOException("Bluetooth is off");
+ mPfd = bluetoothProxy.connectSocket(mDevice, mType,
mUuid, mPort, getSecurityFlags());
synchronized(this)
{
@@ -333,8 +322,13 @@
/*package*/ int bindListen() {
int ret;
if (mSocketState == SocketState.CLOSED) return EBADFD;
+ IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService();
+ if (bluetoothProxy == null) {
+ Log.e(TAG, "bindListen fail, reason: bluetooth is off");
+ return -1;
+ }
try {
- mPfd = sBluetoothProxy.createSocketChannel(mType, mServiceName,
+ mPfd = bluetoothProxy.createSocketChannel(mType, mServiceName,
mUuid, mPort, getSecurityFlags());
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(new Throwable()));
diff --git a/core/java/android/bluetooth/BluetoothTetheringDataTracker.java b/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
index 83d1bda..593b699 100644
--- a/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
+++ b/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
@@ -16,6 +16,9 @@
package android.bluetooth;
+import android.os.IBinder;
+import android.os.ServiceManager;
+import android.os.INetworkManagementService;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.DhcpInfoInternal;
@@ -28,6 +31,11 @@
import android.os.Handler;
import android.os.Message;
import android.util.Log;
+import java.net.InterfaceAddress;
+import android.net.LinkAddress;
+import android.net.RouteInfo;
+import java.net.Inet4Address;
+import android.os.SystemProperties;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
@@ -54,7 +62,6 @@
private NetworkInfo mNetworkInfo;
private BluetoothPan mBluetoothPan;
- private BluetoothDevice mDevice;
private static String mIface;
/* For sending events to connectivity service handler */
@@ -92,8 +99,10 @@
* Begin monitoring connectivity
*/
public void startMonitoring(Context context, Handler target) {
+ Log.d(TAG, "startMonitoring: target: " + target);
mContext = context;
mCsHandler = target;
+ Log.d(TAG, "startMonitoring: mCsHandler: " + mCsHandler);
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
if (adapter != null) {
adapter.getProfileProxy(mContext, mProfileServiceListener, BluetoothProfile.PAN);
@@ -259,38 +268,87 @@
return "net.tcp.buffersize.wifi";
}
+ private static short countPrefixLength(byte [] mask) {
+ short count = 0;
+ for (byte b : mask) {
+ for (int i = 0; i < 8; ++i) {
+ if ((b & (1 << i)) != 0) {
+ ++count;
+ }
+ }
+ }
+ return count;
+ }
- public synchronized void startReverseTether(String iface, BluetoothDevice device) {
+
+ private boolean readLinkProperty(String iface) {
+ String DhcpPrefix = "dhcp." + iface + ".";
+ String ip = SystemProperties.get(DhcpPrefix + "ipaddress");
+ String dns1 = SystemProperties.get(DhcpPrefix + "dns1");
+ String dns2 = SystemProperties.get(DhcpPrefix + "dns2");
+ String gateway = SystemProperties.get(DhcpPrefix + "gateway");
+ String mask = SystemProperties.get(DhcpPrefix + "mask");
+ if(ip.isEmpty() || gateway.isEmpty()) {
+ Log.e(TAG, "readLinkProperty, ip: " + ip + ", gateway: " + gateway + ", can not be empty");
+ return false;
+ }
+ int PrefixLen = countPrefixLength(NetworkUtils.numericToInetAddress(mask).getAddress());
+ mLinkProperties.addLinkAddress(new LinkAddress(NetworkUtils.numericToInetAddress(ip), PrefixLen));
+ RouteInfo ri = new RouteInfo(NetworkUtils.numericToInetAddress(gateway));
+ mLinkProperties.addRoute(ri);
+ if(!dns1.isEmpty())
+ mLinkProperties.addDns(NetworkUtils.numericToInetAddress(dns1));
+ if(!dns2.isEmpty())
+ mLinkProperties.addDns(NetworkUtils.numericToInetAddress(dns2));
+ mLinkProperties.setInterfaceName(iface);
+ return true;
+ }
+ public synchronized void startReverseTether(String iface) {
mIface = iface;
- mDevice = device;
+ Log.d(TAG, "startReverseTether mCsHandler: " + mCsHandler);
Thread dhcpThread = new Thread(new Runnable() {
public void run() {
//TODO(): Add callbacks for failure and success case.
//Currently this thread runs independently.
- DhcpInfoInternal dhcpInfoInternal = new DhcpInfoInternal();
- if (!NetworkUtils.runDhcp(mIface, dhcpInfoInternal)) {
- Log.e(TAG, "DHCP request error:" + NetworkUtils.getDhcpError());
- return;
+ Log.d(TAG, "startReverseTether mCsHandler: " + mCsHandler);
+ String DhcpResultName = "dhcp." + mIface + ".result";;
+ String result = "";
+ Log.d(TAG, "waiting for change of sys prop dhcp result: " + DhcpResultName);
+ for(int i = 0; i < 30*5; i++) {
+ try { Thread.sleep(200); } catch (InterruptedException ie) { }
+ result = SystemProperties.get(DhcpResultName);
+ Log.d(TAG, "read " + DhcpResultName + ": " + result);
+ if(result.equals("failed")) {
+ Log.e(TAG, "startReverseTether, failed to start dhcp service");
+ return;
+ }
+ if(result.equals("ok")) {
+ Log.d(TAG, "startReverseTether, dhcp resut: " + result);
+ if(readLinkProperty(mIface)) {
+
+ mNetworkInfo.setIsAvailable(true);
+ mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null);
+
+ Log.d(TAG, "startReverseTether mCsHandler: " + mCsHandler);
+ if(mCsHandler != null) {
+ Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo);
+ msg.sendToTarget();
+
+ msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
+ msg.sendToTarget();
+ }
+ }
+ return;
+ }
}
- mLinkProperties = dhcpInfoInternal.makeLinkProperties();
- mLinkProperties.setInterfaceName(mIface);
-
- mNetworkInfo.setIsAvailable(true);
- mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null);
-
- Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo);
- msg.sendToTarget();
-
- msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
- msg.sendToTarget();
+ Log.d(TAG, "startReverseTether, dhcp failed, resut: " + result);
}
});
dhcpThread.start();
}
- public synchronized void stopReverseTether(String iface) {
- NetworkUtils.stopDhcp(iface);
-
+ public synchronized void stopReverseTether() {
+ //NetworkUtils.stopDhcp(iface);
mLinkProperties.clear();
mNetworkInfo.setIsAvailable(false);
mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
diff --git a/core/java/android/bluetooth/IBluetoothManager.aidl b/core/java/android/bluetooth/IBluetoothManager.aidl
new file mode 100644
index 0000000..f82da82
--- /dev/null
+++ b/core/java/android/bluetooth/IBluetoothManager.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2012 Google Inc.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.IBluetooth;
+import android.bluetooth.IBluetoothManagerCallback;
+import android.bluetooth.IBluetoothStateChangeCallback;
+
+/**
+ * System private API for talking with the Bluetooth service.
+ *
+ * {@hide}
+ */
+interface IBluetoothManager
+{
+ IBluetooth registerAdapter(in IBluetoothManagerCallback callback);
+ void unregisterAdapter(in IBluetoothManagerCallback callback);
+ void registerStateChangeCallback(in IBluetoothStateChangeCallback callback);
+ void unregisterStateChangeCallback(in IBluetoothStateChangeCallback callback);
+ boolean isEnabled();
+ boolean enable();
+ boolean disable(boolean persist);
+
+ String getAddress();
+ String getName();
+}
diff --git a/core/java/android/bluetooth/IBluetoothManagerCallback.aidl b/core/java/android/bluetooth/IBluetoothManagerCallback.aidl
new file mode 100644
index 0000000..3e795ea
--- /dev/null
+++ b/core/java/android/bluetooth/IBluetoothManagerCallback.aidl
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2012 Google Inc.
+ */
+
+package android.bluetooth;
+
+import android.bluetooth.IBluetooth;
+
+/**
+ * API for Communication between BluetoothAdapter and BluetoothManager
+ *
+ * {@hide}
+ */
+interface IBluetoothManagerCallback {
+ void onBluetoothServiceUp(in IBluetooth bluetoothService);
+ void onBluetoothServiceDown();
+}
\ No newline at end of file
diff --git a/core/java/android/bluetooth/IBluetoothPan.aidl b/core/java/android/bluetooth/IBluetoothPan.aidl
new file mode 100644
index 0000000..b91bd7d
--- /dev/null
+++ b/core/java/android/bluetooth/IBluetoothPan.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2012 Google Inc.
+ */
+package android.bluetooth;
+
+import android.bluetooth.BluetoothDevice;
+
+/**
+ * API for Bluetooth Pan service
+ *
+ * {@hide}
+ */
+interface IBluetoothPan {
+ // Public API
+ boolean isTetheringOn();
+ void setBluetoothTethering(boolean value);
+ boolean connect(in BluetoothDevice device);
+ boolean disconnect(in BluetoothDevice device);
+ List<BluetoothDevice> getConnectedDevices();
+ List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
+ int getConnectionState(in BluetoothDevice device);
+}
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index b64a73a..53bb88a 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -152,6 +152,16 @@
boolean isTetheringStarted();
/**
+ * Start bluetooth reverse tethering services
+ */
+ void startReverseTethering(in String iface);
+
+ /**
+ * Stop currently running bluetooth reserse tethering services
+ */
+ void stopReverseTethering();
+
+ /**
* Tethers the specified interface
*/
void tetherInterface(String iface);