diff options
author | fredc <fredc@broadcom.com> | 2012-04-12 00:02:00 -0700 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2012-07-16 21:20:54 -0700 |
commit | 0f42037eb7b5118015c2caca635538324ccf0ccf (patch) | |
tree | 46a7ba36216a2cb617541ec68f18b413419e148f | |
parent | 919a4c6264b733585152ce1dc6f868c1093d368b (diff) | |
download | frameworks_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
22 files changed, 1232 insertions, 213 deletions
@@ -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() { |