From 10eac971b3a6e5f34a420dd68ebfa796553ad2b9 Mon Sep 17 00:00:00 2001 From: Jaikumar Ganesh Date: Mon, 21 Sep 2009 12:48:51 -0700 Subject: Cache the remote device's service channel. Bluez Device implementation is such that when a device is unpaired, we removes the device and hence there is no way to interact with it unless you pair again. Remote service channel call is used to get the rfcomm channel number which will be used in profiles like OPP which don't require pairing. Change-Id: I868a6cdfdb1b7d3591dd8b66cd0320f41a9c1b92 --- core/java/android/bluetooth/BluetoothUuid.java | 6 +++ core/java/android/server/BluetoothEventLoop.java | 7 ++- core/java/android/server/BluetoothService.java | 57 +++++++++++++++++++++--- 3 files changed, 62 insertions(+), 8 deletions(-) (limited to 'core/java/android') diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java index 0596b21..24ad06a 100644 --- a/core/java/android/bluetooth/BluetoothUuid.java +++ b/core/java/android/bluetooth/BluetoothUuid.java @@ -83,6 +83,12 @@ public final class BluetoothUuid { * @param uuid */ public static boolean isUuidPresent(ParcelUuid[] uuidArray, ParcelUuid uuid) { + if ((uuidArray == null || uuidArray.length == 0) && uuid == null) + return true; + + if (uuidArray == null) + return false; + for (ParcelUuid element: uuidArray) { if (element.equals(uuid)) return true; } diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java index 34921f4..f9ab31c 100644 --- a/core/java/android/server/BluetoothEventLoop.java +++ b/core/java/android/server/BluetoothEventLoop.java @@ -369,6 +369,10 @@ class BluetoothEventLoop { uuid = str.toString(); } mBluetoothService.setRemoteDeviceProperty(address, name, uuid); + + // UUIDs have changed, query remote service channel and update cache. + mBluetoothService.updateDeviceServiceChannelCache(address); + mBluetoothService.sendUuidIntent(address); } else if (name.equals("Paired")) { if (propValues[1].equals("true")) { @@ -537,8 +541,7 @@ class BluetoothEventLoop { String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath); // We don't parse the xml here, instead just query Bluez for the properties. if (result) { - String[] properties = mBluetoothService.getRemoteDeviceProperties(address); - mBluetoothService.addRemoteDeviceProperties(address, properties); + mBluetoothService.updateRemoteDevicePropertiesCache(address); } mBluetoothService.sendUuidIntent(address); } diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java index 26007c5..253b1ab 100644 --- a/core/java/android/server/BluetoothService.java +++ b/core/java/android/server/BluetoothService.java @@ -28,6 +28,7 @@ import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothClass; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHeadset; +import android.bluetooth.BluetoothUuid; import android.bluetooth.IBluetooth; import android.bluetooth.ParcelUuid; import android.content.BroadcastReceiver; @@ -85,6 +86,7 @@ public class BluetoothService extends IBluetooth.Stub { private final Map mAdapterProperties; private final HashMap > mDeviceProperties; + private final HashMap > mDeviceServiceChannelCache; private final ArrayList mUuidIntentTracker; static { @@ -111,6 +113,8 @@ public class BluetoothService extends IBluetooth.Stub { mIsDiscovering = false; mAdapterProperties = new HashMap(); mDeviceProperties = new HashMap>(); + + mDeviceServiceChannelCache = new HashMap>(); mUuidIntentTracker = new ArrayList(); registerForAirplaneMode(); } @@ -880,16 +884,22 @@ public class BluetoothService extends IBluetooth.Stub { // Query for remote device properties, again. // We will need to reload the cache when we switch Bluetooth on / off // or if we crash. - String[] propValues = getRemoteDeviceProperties(address); - if (propValues != null) { - addRemoteDeviceProperties(address, propValues); + if (updateRemoteDevicePropertiesCache(address)) return getRemoteDeviceProperty(address, property); - } } Log.e(TAG, "getRemoteDeviceProperty: " + property + "not present:" + address); return null; } + /* package */ synchronized boolean updateRemoteDevicePropertiesCache(String address) { + String[] propValues = getRemoteDeviceProperties(address); + if (propValues != null) { + addRemoteDeviceProperties(address, propValues); + return true; + } + return false; + } + /* package */ synchronized void addRemoteDeviceProperties(String address, String[] properties) { /* * We get a DeviceFound signal every time RSSI changes or name changes. @@ -924,6 +934,10 @@ public class BluetoothService extends IBluetooth.Stub { propertyValues.put(name, newValue); } mDeviceProperties.put(address, propertyValues); + + // We have added a new remote device or updated its properties. + // Also update the serviceChannel cache. + updateDeviceServiceChannelCache(address); } /* package */ void removeRemoteDeviceProperties(String address) { @@ -1066,14 +1080,23 @@ public class BluetoothService extends IBluetooth.Stub { * @param uuid ParcelUuid of the service attribute * * @return rfcomm channel associated with the service attribute + * -1 on error */ public int getRemoteServiceChannel(String address, ParcelUuid uuid) { mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); if (!BluetoothAdapter.checkBluetoothAddress(address)) { return BluetoothDevice.ERROR; } - return getDeviceServiceChannelNative(getObjectPathFromAddress(address), uuid.toString(), - 0x0004); + // Check if we are recovering from a crash. + if (mDeviceProperties.isEmpty()) { + if (!updateRemoteDevicePropertiesCache(address)) + return -1; + } + + Map value = mDeviceServiceChannelCache.get(address); + if (value != null && value.containsKey(uuid)) + return value.get(uuid); + return -1; } public synchronized boolean setPin(String address, byte[] pin) { @@ -1152,6 +1175,27 @@ public class BluetoothService extends IBluetooth.Stub { return cancelPairingUserInputNative(address, data.intValue()); } + public void updateDeviceServiceChannelCache(String address) { + ParcelUuid[] deviceUuids = getRemoteUuids(address); + // We are storing the rfcomm channel numbers only for the uuids + // we are interested in. + int channel; + ParcelUuid[] interestedUuids = {BluetoothUuid.Handsfree, + BluetoothUuid.HSP, + BluetoothUuid.ObexObjectPush}; + + Map value = new HashMap(); + for (ParcelUuid uuid: interestedUuids) { + if (BluetoothUuid.isUuidPresent(deviceUuids, uuid)) { + channel = + getDeviceServiceChannelNative(getObjectPathFromAddress(address), uuid.toString(), + 0x0004); + value.put(uuid, channel); + } + } + mDeviceServiceChannelCache.put(address, value); + } + private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -1366,4 +1410,5 @@ public class BluetoothService extends IBluetooth.Stub { private native boolean setDevicePropertyBooleanNative(String objectPath, String key, int value); private native boolean createDeviceNative(String address); private native boolean discoverServicesNative(String objectPath, String pattern); + } -- cgit v1.1