summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorfredc <fredc@broadcom.com>2012-04-12 00:02:00 -0700
committerAndroid (Google) Code Review <android-gerrit@google.com>2012-07-16 21:20:54 -0700
commit0f42037eb7b5118015c2caca635538324ccf0ccf (patch)
tree46a7ba36216a2cb617541ec68f18b413419e148f
parent919a4c6264b733585152ce1dc6f868c1093d368b (diff)
downloadframeworks_base-0f42037eb7b5118015c2caca635538324ccf0ccf.zip
frameworks_base-0f42037eb7b5118015c2caca635538324ccf0ccf.tar.gz
frameworks_base-0f42037eb7b5118015c2caca635538324ccf0ccf.tar.bz2
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
-rw-r--r--Android.mk3
-rw-r--r--api/current.txt2
-rw-r--r--core/java/android/bluetooth/BluetoothA2dp.java63
-rwxr-xr-xcore/java/android/bluetooth/BluetoothAdapter.java147
-rwxr-xr-xcore/java/android/bluetooth/BluetoothDevice.java57
-rw-r--r--core/java/android/bluetooth/BluetoothHeadset.java65
-rw-r--r--core/java/android/bluetooth/BluetoothHealth.java63
-rwxr-xr-xcore/java/android/bluetooth/BluetoothInputDevice.java64
-rw-r--r--core/java/android/bluetooth/BluetoothPan.java119
-rw-r--r--core/java/android/bluetooth/BluetoothSocket.java24
-rw-r--r--core/java/android/bluetooth/BluetoothTetheringDataTracker.java100
-rw-r--r--core/java/android/bluetooth/IBluetoothManager.aidl28
-rw-r--r--core/java/android/bluetooth/IBluetoothManagerCallback.aidl17
-rw-r--r--core/java/android/bluetooth/IBluetoothPan.aidl22
-rw-r--r--core/java/android/os/INetworkManagementService.aidl10
-rw-r--r--core/res/AndroidManifest.xml5
-rw-r--r--data/etc/platform.xml4
-rw-r--r--services/java/com/android/server/BluetoothManagerService.java542
-rw-r--r--services/java/com/android/server/NetworkManagementService.java29
-rw-r--r--services/java/com/android/server/SystemServer.java15
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java3
-rw-r--r--services/java/com/android/server/power/ShutdownThread.java63
22 files changed, 1232 insertions, 213 deletions
diff --git a/Android.mk b/Android.mk
index 8481e72..5fb66ab 100644
--- a/Android.mk
+++ b/Android.mk
@@ -93,6 +93,9 @@ LOCAL_SRC_FILES += \
core/java/android/bluetooth/IBluetoothHealth.aidl \
core/java/android/bluetooth/IBluetoothHealthCallback.aidl \
core/java/android/bluetooth/IBluetoothInputDevice.aidl \
+ core/java/android/bluetooth/IBluetoothPan.aidl \
+ core/java/android/bluetooth/IBluetoothManager.aidl \
+ core/java/android/bluetooth/IBluetoothManagerCallback.aidl \
core/java/android/bluetooth/IBluetoothPbap.aidl \
core/java/android/bluetooth/IBluetoothStateChangeCallback.aidl \
core/java/android/content/IClipboard.aidl \
diff --git a/api/current.txt b/api/current.txt
index 3bc4a76..e5e06d1 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -72,6 +72,7 @@ package android {
field public static final java.lang.String MODIFY_PHONE_STATE = "android.permission.MODIFY_PHONE_STATE";
field public static final java.lang.String MOUNT_FORMAT_FILESYSTEMS = "android.permission.MOUNT_FORMAT_FILESYSTEMS";
field public static final java.lang.String MOUNT_UNMOUNT_FILESYSTEMS = "android.permission.MOUNT_UNMOUNT_FILESYSTEMS";
+ field public static final java.lang.String NET_TUNNELING = "android.permission.NET_TUNNELING";
field public static final java.lang.String NFC = "android.permission.NFC";
field public static final deprecated java.lang.String PERSISTENT_ACTIVITY = "android.permission.PERSISTENT_ACTIVITY";
field public static final java.lang.String PROCESS_OUTGOING_CALLS = "android.permission.PROCESS_OUTGOING_CALLS";
@@ -4438,6 +4439,7 @@ package android.appwidget {
package android.bluetooth {
public final class BluetoothA2dp implements android.bluetooth.BluetoothProfile {
+ method public void finalize();
method public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
method public int getConnectionState(android.bluetooth.BluetoothDevice);
method public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]);
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 @@ public final class BluetoothA2dp implements BluetoothProfile {
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 @@ public final class BluetoothA2dp implements BluetoothProfile {
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 @@ public final class BluetoothA2dp implements BluetoothProfile {
/*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 @@ public final class BluetoothA2dp implements BluetoothProfile {
* 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 @@ import java.util.UUID;
*/
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 final class BluetoothAdapter {
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 @@ public final class BluetoothAdapter {
*/
private static BluetoothAdapter sAdapter;
- private final IBluetooth mService;
+ private final IBluetoothManager mManagerService;
+ private IBluetooth mService;
private Handler mServiceRecordHandler;
@@ -367,10 +368,10 @@ public final class BluetoothAdapter {
*/
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 @@ public final class BluetoothAdapter {
/**
* 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 @@ public final class BluetoothAdapter {
* @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 @@ public final class BluetoothAdapter {
* @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 @@ public final class BluetoothAdapter {
* @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 @@ public final class BluetoothAdapter {
* 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 final class BluetoothAdapter {
*/
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 @@ public final class BluetoothAdapter {
* @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 final class BluetoothAdapter {
*/
public String getAddress() {
try {
- return mService.getAddress();
+ return mManagerService.getAddress();
} catch (RemoteException e) {Log.e(TAG, "", e);}
return null;
}
@@ -563,7 +587,7 @@ public final class BluetoothAdapter {
*/
public String getName() {
try {
- return mService.getName();
+ return mManagerService.getName();
} catch (RemoteException e) {Log.e(TAG, "", e);}
return null;
}
@@ -579,7 +603,9 @@ public final class BluetoothAdapter {
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 final class BluetoothAdapter {
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 final class BluetoothAdapter {
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 final class BluetoothAdapter {
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 final class BluetoothAdapter {
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 final class BluetoothAdapter {
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 final class BluetoothAdapter {
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 final class BluetoothAdapter {
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 final class BluetoothAdapter {
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 @@ public final class BluetoothAdapter {
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 final class BluetoothAdapter {
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 final class BluetoothAdapter {
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 @@ public final class BluetoothAdapter {
}
}
+ 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 @@ public final class BluetoothAdapter {
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 @@ public final class BluetoothAdapter {
}
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 @@ import java.util.UUID;
*/
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 @@ public final class BluetoothDevice implements Parcelable {
/*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 @@ public final class BluetoothDevice implements Parcelable {
* @return Bluetooth hardware address as string
*/
public String getAddress() {
+ if (DBG) Log.d(TAG, "mAddress: " + mAddress);
return mAddress;
}
@@ -575,6 +574,10 @@ public final class BluetoothDevice implements Parcelable {
* @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 @@ public final class BluetoothDevice implements Parcelable {
* @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 @@ public final class BluetoothDevice implements Parcelable {
* @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 @@ public final class BluetoothDevice implements Parcelable {
* @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 @@ public final class BluetoothDevice implements Parcelable {
* @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 @@ public final class BluetoothDevice implements Parcelable {
* @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 @@ public final class BluetoothDevice implements Parcelable {
* @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 @@ public final class BluetoothDevice implements Parcelable {
* @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 @@ public final class BluetoothDevice implements Parcelable {
* 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 @@ public final class BluetoothDevice implements Parcelable {
/** @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 @@ public final class BluetoothDevice implements Parcelable {
/** @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 @@ public final class BluetoothDevice implements Parcelable {
/** @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 2df33a6..541b69f 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -45,7 +45,7 @@ import java.util.List;
*/
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 @@ public final class BluetoothHeadset implements BluetoothProfile {
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 @@ public final class BluetoothHeadset implements BluetoothProfile {
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 @@ public final class BluetoothHeadset implements BluetoothProfile {
*/
/*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 @@ import java.util.List;
*/
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 @@ public final class BluetoothHealth implements BluetoothProfile {
/** @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 @@ public final class BluetoothHealth implements BluetoothProfile {
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 @@ public final class BluetoothHealth implements BluetoothProfile {
/*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 @@ import java.util.List;
*/
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 @@ public final class BluetoothInputDevice implements BluetoothProfile {
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 @@ public final class BluetoothInputDevice implements BluetoothProfile {
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 @@ public final class BluetoothInputDevice implements BluetoothProfile {
/*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 @@ package android.bluetooth;
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 android.util.Log;
import java.util.ArrayList;
import java.util.List;
-
/**
* This class provides the APIs to control the Bluetooth Pan
* Profile.
@@ -41,7 +43,7 @@ import java.util.List;
*/
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 final class BluetoothPan implements BluetoothProfile {
*/
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 final class BluetoothPan implements BluetoothProfile {
*/
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 final class BluetoothPan implements BluetoothProfile {
*/
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 final class BluetoothPan implements BluetoothProfile {
*/
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 final class BluetoothPan implements BluetoothProfile {
*/
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 final class BluetoothPan implements BluetoothProfile {
*/
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 final class BluetoothPan implements BluetoothProfile {
*/
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 @@ public final class BluetoothSocket implements Closeable {
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 @@ public final class BluetoothSocket implements Closeable {
}
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 @@ public final class BluetoothSocket implements Closeable {
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 @@ public final class BluetoothSocket implements Closeable {
/*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.net.NetworkUtils;
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 @@ public class BluetoothTetheringDataTracker implements NetworkStateTracker {
private NetworkInfo mNetworkInfo;
private BluetoothPan mBluetoothPan;
- private BluetoothDevice mDevice;
private static String mIface;
/* For sending events to connectivity service handler */
@@ -92,8 +99,10 @@ public class BluetoothTetheringDataTracker implements NetworkStateTracker {
* 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 @@ public class BluetoothTetheringDataTracker implements NetworkStateTracker {
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 @@ interface INetworkManagementService
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);
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index cdc5ad4..06414d9 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1409,6 +1409,11 @@
android:description="@string/permdesc_devicePower"
android:protectionLevel="signature" />
+ <!-- Allows low-level access to tun tap driver -->
+ <permission android:name="android.permission.NET_TUNNELING"
+ android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+ android:protectionLevel="signature" />
+
<!-- Run as a manufacturer test application, running as the root user.
Only available when the device is running in manufacturer test mode. -->
<permission android:name="android.permission.FACTORY_TEST"
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 4b93e74..38a75b6 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -42,6 +42,10 @@
<group gid="net_bt" />
</permission>
+ <permission name="android.permission.NET_TUNNELING" >
+ <group gid="vpn" />
+ </permission>
+
<permission name="android.permission.INTERNET" >
<group gid="inet" />
</permission>
diff --git a/services/java/com/android/server/BluetoothManagerService.java b/services/java/com/android/server/BluetoothManagerService.java
new file mode 100644
index 0000000..37790a3
--- /dev/null
+++ b/services/java/com/android/server/BluetoothManagerService.java
@@ -0,0 +1,542 @@
+/*
+ * Copyright (C) 2012 Google Inc.
+ */
+
+package com.android.server;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.IBluetooth;
+import android.bluetooth.IBluetoothManager;
+import android.bluetooth.IBluetoothManagerCallback;
+import android.bluetooth.IBluetoothStateChangeCallback;
+
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.os.Handler;
+
+import android.os.IBinder;
+import android.os.Message;
+import android.os.RemoteException;
+import android.provider.Settings;
+import android.util.Log;
+import java.util.List;
+import java.util.ArrayList;
+
+class BluetoothManagerService extends IBluetoothManager.Stub {
+ private static final String TAG = "BluetoothManagerService";
+ private static final boolean DBG = true;
+
+ private static final boolean ALWAYS_SYNC_NAME_ADDRESS=true; //If true, always load name and address
+
+ private static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN;
+ private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
+
+ private static final String ACTION_SERVICE_STATE_CHANGED="com.android.bluetooth.btservice.action.STATE_CHANGED";
+ private static final String EXTRA_ACTION="action";
+
+ private static final String SECURE_SETTINGS_BLUETOOTH_ADDRESS="bluetooth_address";
+ private static final String SECURE_SETTINGS_BLUETOOTH_NAME="bluetooth_name";
+
+ private static final int TIMEOUT_BIND_MS = 3000; //Maximum msec to wait for a bind
+ private static final int TIMEOUT_SAVE_MS = 500; //Maximum msec to wait for a save
+
+ private static final int MESSAGE_ENABLE = 1;
+ private static final int MESSAGE_DISABLE = 2;
+ private static final int MESSAGE_REGISTER_ADAPTER = 3;
+ private static final int MESSAGE_UNREGISTER_ADAPTER = 4;
+ private static final int MESSAGE_REGISTER_STATE_CHANGE_CALLBACK = 5;
+ private static final int MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK = 6;
+ private static final int MESSAGE_BLUETOOTH_SERVICE_CONNECTED = 11;
+ private static final int MESSAGE_BLUETOOTH_ON = 12;
+ private static final int MESSAGE_BLUETOOTH_OFF = 14;
+ private static final int MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED = 15;
+ private static final int MESSAGE_TIMEOUT_BIND =100;
+ private static final int MESSAGE_TIMEOUT_UNBIND =101;
+ private static final int MESSAGE_GET_NAME_AND_ADDRESS=200;
+ private static final int MESSAGE_SAVE_NAME_AND_ADDRESS=201;
+ private static final int MAX_SAVE_RETRIES=3;
+
+ private final Context mContext;
+ private String mAddress;
+ private String mName;
+ private ContentResolver mContentResolver;
+ private List<IBluetoothManagerCallback> mCallbacks;
+ private List<IBluetoothStateChangeCallback> mStateChangeCallbacks;
+
+ IntentFilter mFilter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
+ private BroadcastReceiver mReceiver = new BroadcastReceiver() {
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if(BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
+ int state= intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
+ if (state == BluetoothAdapter.STATE_OFF) {
+ Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_OFF);
+ mHandler.sendMessage(msg);
+ } else if (state == BluetoothAdapter.STATE_ON) {
+ Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_ON);
+ mHandler.sendMessage(msg);
+ }
+ } else if (BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED.equals(action)) {
+ String newName = intent.getStringExtra(BluetoothAdapter.EXTRA_LOCAL_NAME);
+ Log.d(TAG, "Bluetooth Adapter name changed to " + newName);
+ if (newName != null) {
+ storeNameAndAddress(newName, null);
+ }
+ }
+ }
+ };
+
+ BluetoothManagerService(Context context) {
+ mContext = context;
+ mBluetooth = null;
+ mBinding = false;
+ mUnbinding = false;
+ mAddress = null;
+ mName = null;
+ mContentResolver = context.getContentResolver();
+ mCallbacks = new ArrayList<IBluetoothManagerCallback>();
+ mStateChangeCallbacks = new ArrayList<IBluetoothStateChangeCallback>();
+ mContext.registerReceiver(mReceiver, mFilter);
+
+ int airplaneModeOn = Settings.System.getInt(mContentResolver,
+ Settings.System.AIRPLANE_MODE_ON, 0);
+ int bluetoothOn = Settings.Secure.getInt(mContentResolver,
+ Settings.Secure.BLUETOOTH_ON, 0);
+ if (DBG) Log.d(TAG, "airplane mode: " + airplaneModeOn + " bluetoothOn: " + bluetoothOn);
+
+ loadStoredNameAndAddress();
+ if (airplaneModeOn == 0 && bluetoothOn!= 0) {
+ //Enable
+ if (DBG) Log.d(TAG, "Autoenabling Bluetooth.");
+ enable();
+ } else if (ALWAYS_SYNC_NAME_ADDRESS || !isNameAndAddressSet()) {
+ if (DBG) Log.d(TAG,"Retrieving name and address...");
+ getNameAndAddress();
+ }
+ }
+
+ private boolean isNameAndAddressSet() {
+ return mName !=null && mAddress!= null && mName.length()>0 && mAddress.length()>0;
+ }
+
+ private void loadStoredNameAndAddress() {
+ if (DBG) Log.d(TAG, "Loading stored name and address");
+ mName = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME);
+ mAddress = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS);
+ if (mName == null || mAddress == null) {
+ if (DBG) Log.d(TAG, "Name or address not cached...");
+ }
+ }
+
+ private void storeNameAndAddress(String name, String address) {
+ if (name != null) {
+ Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, name);
+ if (DBG) Log.d(TAG,"Stored name: " + Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_NAME));
+ mName = name;
+ }
+
+ if (address != null) {
+ Settings.Secure.putString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS, address);
+ if (DBG) Log.d(TAG,"Stored address: " + Settings.Secure.getString(mContentResolver,SECURE_SETTINGS_BLUETOOTH_ADDRESS));
+ mAddress=address;
+ }
+ }
+
+ public IBluetooth registerAdapter(IBluetoothManagerCallback callback){
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
+ "Need BLUETOOTH permission");
+ Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_ADAPTER);
+ msg.obj = callback;
+ mHandler.sendMessage(msg);
+ synchronized(mConnection) {
+ return mBluetooth;
+ }
+ }
+
+ public void unregisterAdapter(IBluetoothManagerCallback callback) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
+ "Need BLUETOOTH permission");
+ Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_ADAPTER);
+ msg.obj = callback;
+ mHandler.sendMessage(msg);
+ }
+
+ public void registerStateChangeCallback(IBluetoothStateChangeCallback callback) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
+ "Need BLUETOOTH permission");
+ Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_STATE_CHANGE_CALLBACK);
+ msg.obj = callback;
+ mHandler.sendMessage(msg);
+ }
+
+ public void unregisterStateChangeCallback(IBluetoothStateChangeCallback callback) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM,
+ "Need BLUETOOTH permission");
+ Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK);
+ msg.obj = callback;
+ mHandler.sendMessage(msg);
+ }
+
+ public boolean isEnabled() {
+ synchronized(mConnection) {
+ try {
+ return (mBluetooth != null && mBluetooth.isEnabled());
+ } catch (RemoteException e) {
+ Log.e(TAG, "isEnabled()", e);
+ }
+ }
+ return false;
+ }
+
+ public void getNameAndAddress() {
+ synchronized(mConnection) {
+ if (mBinding) return ;
+ mBinding = true;
+ }
+ Message msg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
+ mHandler.sendMessage(msg);
+ }
+
+ public boolean enable() {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+ "Need BLUETOOTH ADMIN permission");
+ synchronized(mConnection) {
+ //if (mBluetooth != null) return false; [fc] always allow an enable() to occur.
+ //If service is bound, we should not assume that bluetooth is enabled. What if
+ //Bluetooth never turned on?
+ if (mBinding) return true;
+ mBinding = true;
+ }
+ Message msg = mHandler.obtainMessage(MESSAGE_ENABLE);
+ //msg.obj = new Boolean(true);
+ mHandler.sendMessage(msg);
+ return true;
+ }
+
+ public boolean disable(boolean persist) {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+ "Need BLUETOOTH ADMIN permissicacheNameAndAddresson");
+ synchronized(mConnection) {
+ if (mBluetooth == null) return false;
+ //if (mUnbinding) return true;
+ //mUnbinding = true;
+ }
+ Message msg = mHandler.obtainMessage(MESSAGE_DISABLE);
+ msg.obj = new Boolean(persist);
+ mHandler.sendMessage(msg);
+ return true;
+ }
+
+ public void unbindAndFinish(boolean sendStop) {
+ synchronized (mConnection) {
+ if (mUnbinding) return;
+ mUnbinding = true;
+ if (mIsConnected) {
+ if (sendStop) {
+ if (DBG) Log.d(TAG,"Sending stop request.");
+ Intent i = new Intent(IBluetooth.class.getName());
+ i.putExtra(EXTRA_ACTION, ACTION_SERVICE_STATE_CHANGED);
+ i.putExtra(BluetoothAdapter.EXTRA_STATE,BluetoothAdapter.STATE_OFF);
+ mContext.startService(i);
+ }
+ if (DBG) Log.d(TAG, "Sending unbind request.");
+ mContext.unbindService(mConnection);
+ mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED));
+ }
+ }
+ }
+
+ public String getAddress() {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+ "Need BLUETOOTH ADMIN permission");
+ return mAddress;
+ }
+ public String getName() {
+ mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
+ "Need BLUETOOTH ADMIN permission");
+ return mName;
+ }
+
+ private IBluetooth mBluetooth;
+ private boolean mBinding;
+ private boolean mUnbinding;
+ public boolean mIsConnected;
+
+ private class BluetoothServiceConnection implements ServiceConnection {
+
+ private boolean mGetNameAddressOnly;
+
+ public void setGetNameAddressOnly(boolean getOnly) {
+ mGetNameAddressOnly = getOnly;
+ }
+
+ public boolean isGetNameAddressOnly() {
+ return mGetNameAddressOnly;
+ }
+
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ if (DBG) Log.d(TAG, "Proxy object connected");
+ Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
+ msg.obj = service;
+ mHandler.sendMessage(msg);
+ }
+
+ public void onServiceDisconnected(ComponentName className) {
+ if (DBG) Log.d(TAG, "Proxy object disconnected");
+ // Called if we unexpected disconnected.
+ Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED);
+ mHandler.sendMessage(msg);
+ }
+ }
+
+ private BluetoothServiceConnection mConnection = new BluetoothServiceConnection();
+
+ private final Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ if (DBG) Log.d (TAG, "Message: " + msg.what);
+
+ switch (msg.what) {
+ case MESSAGE_GET_NAME_AND_ADDRESS: {
+ if (mBluetooth == null) {
+ //Start bind request
+ if (!mIsConnected) {
+ if (DBG) Log.d(TAG, "Binding to service to get name and address");
+ mConnection.setGetNameAddressOnly(true);
+ //Start bind timeout and bind
+ Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
+ mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
+ Intent i = new Intent(IBluetooth.class.getName());
+ if (!mContext.bindService(i, mConnection,
+ Context.BIND_AUTO_CREATE)) {
+ mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
+ Log.e(TAG, "fail to bind to: " + IBluetooth.class.getName());
+ }
+ }
+ } else {
+ Message saveMsg= mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
+ mHandler.sendMessage(saveMsg);
+ }
+ }
+ break;
+ case MESSAGE_SAVE_NAME_AND_ADDRESS: {
+ if (mBluetooth != null) {
+ String name = null;
+ String address = null;
+ try {
+ name = mBluetooth.getName();
+ address = mBluetooth.getAddress();
+ } catch (RemoteException re) {
+ Log.e(TAG,"",re);
+ }
+
+ if (name != null && address != null) {
+ storeNameAndAddress(name,address);
+ unbindAndFinish(false);
+ } else {
+ if (msg.arg1 < MAX_SAVE_RETRIES) {
+ Message retryMsg = mHandler.obtainMessage(MESSAGE_SAVE_NAME_AND_ADDRESS);
+ retryMsg.arg1= 1+msg.arg1;
+ if (DBG) Log.d(TAG,"Retrying name/address remote retrieval and save.....Retry count =" + retryMsg.arg1);
+ mHandler.sendMessageDelayed(retryMsg, TIMEOUT_SAVE_MS);
+ } else {
+ Log.w(TAG,"Maximum name/address remote retrieval retry exceeded");
+ unbindAndFinish(false);
+ }
+ }
+ }
+ }
+ break;
+ case MESSAGE_ENABLE: {
+ if (mBluetooth == null) {
+ //Start bind request
+ if (!mIsConnected) {
+ //Start bind timeout and bind
+ Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
+ mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
+ Intent i = new Intent(IBluetooth.class.getName());
+ i.putExtra(EXTRA_ACTION, ACTION_SERVICE_STATE_CHANGED);
+ i.putExtra(BluetoothAdapter.EXTRA_STATE,BluetoothAdapter.STATE_ON);
+ mContext.startService(i);
+ mConnection.setGetNameAddressOnly(false);
+ if (!mContext.bindService(i, mConnection,
+ Context.BIND_AUTO_CREATE)) {
+ mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
+ Log.e(TAG, "fail to bind to: " + IBluetooth.class.getName());
+ }
+ }
+ } else {
+ //Check if name and address is loaded if not get it first.
+ if (ALWAYS_SYNC_NAME_ADDRESS || !isNameAndAddressSet()) {
+ try {
+ if (DBG) Log.d(TAG,"Bluetooth Proxy available: getting name and address prior to enable.");
+ storeNameAndAddress(mBluetooth.getName(),mBluetooth.getAddress());
+ } catch (RemoteException e) {Log.e(TAG, "", e);};
+ }
+ try {
+ mBluetooth.enable();
+ } catch (RemoteException e) {Log.e(TAG, "", e);};
+ }
+ // TODO(BT) what if service failed to start:
+ // [fc] fixed: watch for bind timeout and handle accordingly
+ // TODO(BT) persist the setting depending on argument
+ // [fc]: let AdapterServiceHandle
+ }
+ break;
+ case MESSAGE_DISABLE:
+ if (mBluetooth != null ) {
+ boolean persist = (Boolean)msg.obj;
+ try {
+ mConnection.setGetNameAddressOnly(false);
+ mBluetooth.disable(persist);
+ //We will only unbind once we are sure that Bluetooth is OFFMESSAGE_TIMEOUT_UNBIND
+ //mContext.unbindService(mConnection);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error disabling Bluetooth", e);
+ }
+ }
+
+ // TODO(BT) what if service failed to stop:
+ // [fc] fixed: watch for disable event and unbind accordingly
+ // TODO(BT) persist the setting depending on argument
+ // [fc]: let AdapterServiceHandle
+
+ break;
+ case MESSAGE_REGISTER_ADAPTER:
+ {
+ IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
+ mCallbacks.add(callback);
+ }
+ break;
+ case MESSAGE_UNREGISTER_ADAPTER:
+ {
+ IBluetoothManagerCallback callback = (IBluetoothManagerCallback) msg.obj;
+ mCallbacks.remove(callback);
+ }
+ break;
+ case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK:
+ {
+ IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
+ mStateChangeCallbacks.add(callback);
+ }
+ break;
+ case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK:
+ {
+ IBluetoothStateChangeCallback callback = (IBluetoothStateChangeCallback) msg.obj;
+ mStateChangeCallbacks.remove(callback);
+ }
+ break;
+ case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
+ {
+ if (DBG) Log.d(TAG,"Bluetooth service connnected!");
+ //Remove timeout
+ mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
+
+ IBinder service = (IBinder) msg.obj;
+ synchronized(mConnection) {
+ mIsConnected=true;
+ mBinding = false;
+ mBluetooth = IBluetooth.Stub.asInterface(service);
+ }
+
+ if (mConnection.isGetNameAddressOnly()) {
+ //Request GET NAME AND ADDRESS
+ Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
+ mHandler.sendMessage(getMsg);
+ return;
+ }
+
+ //Otherwise do the enable
+ if (DBG) Log.d(TAG,"Requesting Bluetooth enable...");
+ try {
+ for (IBluetoothManagerCallback callback : mCallbacks) {
+ callback.onBluetoothServiceUp(mBluetooth);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ }
+
+ //Request Enable
+ Message enableMsg = mHandler.obtainMessage(MESSAGE_ENABLE);
+ //enableMsg.obj = new Boolean(false);
+ mHandler.sendMessage(enableMsg);
+ }
+ break;
+ case MESSAGE_TIMEOUT_BIND:
+ {
+ Log.e(TAG, "Timeout while trying to bind to Bluetooth Service");
+ synchronized(mConnection) {
+ mBinding = false;
+ }
+ }
+ break;
+
+ case MESSAGE_BLUETOOTH_ON:
+ {
+ if (DBG) Log.d(TAG, "Bluetooth is on!!!");
+ try {
+ for (IBluetoothStateChangeCallback callback : mStateChangeCallbacks) {
+ callback.onBluetoothStateChange(true);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ }
+ }
+ break;
+
+ case MESSAGE_BLUETOOTH_OFF:
+ {
+ if (DBG) Log.d(TAG, "Bluetooth is off. Unbinding...");
+
+ try {
+ for (IBluetoothStateChangeCallback callback : mStateChangeCallbacks) {
+ callback.onBluetoothStateChange(false);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ }
+ unbindAndFinish(true);
+ }
+ case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED:
+ {
+ boolean isUnexpectedDisconnect = false;
+ synchronized(mConnection) {
+ mBluetooth = null;
+ mIsConnected=false;
+ if (mUnbinding) {
+ mUnbinding = false;
+ } else {
+ isUnexpectedDisconnect = true;
+ }
+ }
+ if (!isUnexpectedDisconnect &&!mConnection.isGetNameAddressOnly()) {
+ if (DBG) Log.d(TAG,"Service finished unbinding. Calling callbacks...");
+ try {
+ for (IBluetoothManagerCallback callback : mCallbacks) {
+ callback.onBluetoothServiceDown();
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ }
+ }
+ }
+ break;
+ case MESSAGE_TIMEOUT_UNBIND:
+ {
+ Log.e(TAG, "Timeout while trying to unbind to Bluetooth Service");
+ synchronized(mConnection) {
+ mUnbinding = false;
+ }
+ }
+ break;
+ }
+ }
+ };
+}
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index 09792f5..ccba0d2 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -78,6 +78,7 @@ import java.util.Map;
import java.util.NoSuchElementException;
import java.util.StringTokenizer;
import java.util.concurrent.CountDownLatch;
+import android.bluetooth.BluetoothTetheringDataTracker;
/**
* @hide
@@ -779,6 +780,34 @@ public class NetworkManagementService extends INetworkManagementService.Stub
event.checkCode(TetherStatusResult);
return event.getMessage().endsWith("started");
}
+ public void startReverseTethering(String iface)
+ throws IllegalStateException {
+ if (DBG) Slog.d(TAG, "startReverseTethering in");
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
+ // cmd is "tether start first_start first_stop second_start second_stop ..."
+ // an odd number of addrs will fail
+ String cmd = "tether start-reverse";
+ cmd += " " + iface;
+ if (DBG) Slog.d(TAG, "startReverseTethering cmd: " + cmd);
+ try {
+ mConnector.doCommand(cmd);
+ } catch (NativeDaemonConnectorException e) {
+ throw new IllegalStateException("Unable to communicate to native daemon");
+ }
+ BluetoothTetheringDataTracker.getInstance().startReverseTether(iface);
+
+ }
+ public void stopReverseTethering() throws IllegalStateException {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
+ try {
+ mConnector.doCommand("tether stop-reverse");
+ } catch (NativeDaemonConnectorException e) {
+ throw new IllegalStateException("Unable to communicate to native daemon to stop tether");
+ }
+ BluetoothTetheringDataTracker.getInstance().stopReverseTether();
+ }
@Override
public void tetherInterface(String iface) {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 2393957..f4a5f5b 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -128,6 +128,7 @@ class ServerThread extends Thread {
IPackageManager pm = null;
Context context = null;
WindowManagerService wm = null;
+ BluetoothManagerService bluetooth = null;
DockObserver dock = null;
UsbService usb = null;
SerialService serial = null;
@@ -241,17 +242,9 @@ class ServerThread extends Thread {
} else if (factoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
Slog.i(TAG, "No Bluetooth Service (factory test)");
} else {
- int airplaneModeOn = Settings.System.getInt(mContentResolver,
- Settings.System.AIRPLANE_MODE_ON, 0);
- int bluetoothOn = Settings.Secure.getInt(mContentResolver,
- Settings.Secure.BLUETOOTH_ON, 0);
- BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
- // TODO(BT): This will not work as the Bluetooth process is not
- // up. Depending on the process architecture, BluetoothAdapter
- // will have to bind to the service.
- if (adapter != null && airplaneModeOn == 0 && bluetoothOn != 0) {
- adapter.enable();
- }
+ Slog.i(TAG, "Bluetooth Manager Service");
+ bluetooth = new BluetoothManagerService(context);
+ ServiceManager.addService(BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE, bluetooth);
}
} catch (RuntimeException e) {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 60085f4..be05cc7 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -12931,7 +12931,8 @@ public final class ActivityManagerService extends ActivityManagerNative
* processes) from sending protected broadcasts.
*/
if (callingUid == Process.SYSTEM_UID || callingUid == Process.PHONE_UID
- || callingUid == Process.SHELL_UID || callingUid == 0) {
+ || callingUid == Process.SHELL_UID || callingUid == Process.BLUETOOTH_UID ||
+ callingUid == 0) {
// Always okay.
} else if (callerApp == null || !callerApp.persistent) {
try {
diff --git a/services/java/com/android/server/power/ShutdownThread.java b/services/java/com/android/server/power/ShutdownThread.java
index d5b266a..5715151 100644
--- a/services/java/com/android/server/power/ShutdownThread.java
+++ b/services/java/com/android/server/power/ShutdownThread.java
@@ -23,7 +23,7 @@ import android.app.Dialog;
import android.app.IActivityManager;
import android.app.ProgressDialog;
import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.IBluetooth;
+import android.bluetooth.IBluetoothManager;
import android.nfc.NfcAdapter;
import android.nfc.INfcAdapter;
import android.content.BroadcastReceiver;
@@ -324,67 +324,6 @@ public final class ShutdownThread extends Thread {
} catch (RemoteException e) {
}
}
-
- final ITelephony phone =
- ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
- final IBluetooth bluetooth =
- IBluetooth.Stub.asInterface(ServiceManager.checkService(
- BluetoothAdapter.BLUETOOTH_SERVICE));
-
- final IMountService mount =
- IMountService.Stub.asInterface(
- ServiceManager.checkService("mount"));
-
- try {
- bluetoothOff = bluetooth == null ||
- bluetooth.getState() == BluetoothAdapter.STATE_OFF;
- if (!bluetoothOff) {
- Log.w(TAG, "Disabling Bluetooth...");
- bluetooth.disable(false); // disable but don't persist new state
- }
- } catch (RemoteException ex) {
- Log.e(TAG, "RemoteException during bluetooth shutdown", ex);
- bluetoothOff = true;
- }
-
- try {
- radioOff = phone == null || !phone.isRadioOn();
- if (!radioOff) {
- Log.w(TAG, "Turning off radio...");
- phone.setRadio(false);
- }
- } catch (RemoteException ex) {
- Log.e(TAG, "RemoteException during radio shutdown", ex);
- radioOff = true;
- }
-
- Log.i(TAG, "Waiting for Bluetooth and Radio...");
-
- // Wait a max of 32 seconds for clean shutdown
- for (int i = 0; i < MAX_NUM_PHONE_STATE_READS; i++) {
- if (!bluetoothOff) {
- try {
- bluetoothOff =
- bluetooth.getState() == BluetoothAdapter.STATE_OFF;
- } catch (RemoteException ex) {
- Log.e(TAG, "RemoteException during bluetooth shutdown", ex);
- bluetoothOff = true;
- }
- }
- if (!radioOff) {
- try {
- radioOff = !phone.isRadioOn();
- } catch (RemoteException ex) {
- Log.e(TAG, "RemoteException during radio shutdown", ex);
- radioOff = true;
- }
- }
- if (radioOff && bluetoothOff) {
- Log.i(TAG, "Radio and Bluetooth shutdown complete.");
- break;
- }
- SystemClock.sleep(PHONE_STATE_POLL_SLEEP_MSEC);
- }
// Shutdown MountService to ensure media is in a safe state
IMountShutdownObserver observer = new IMountShutdownObserver.Stub() {