summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMichael Chan <mchan@android.com>2009-09-20 18:18:27 -0700
committerMichael Chan <mchan@android.com>2009-09-22 15:37:14 -0700
commit2aef1f3c814b1f8aa00aeefff35caf293c738702 (patch)
tree228cfc552861d4b8a349d485da4de50fa4387bc1 /src
parentd459bebd89756a8b735feb6f27bd864b0427feb7 (diff)
downloadpackages_apps_settings-2aef1f3c814b1f8aa00aeefff35caf293c738702.zip
packages_apps_settings-2aef1f3c814b1f8aa00aeefff35caf293c738702.tar.gz
packages_apps_settings-2aef1f3c814b1f8aa00aeefff35caf293c738702.tar.bz2
b/2126036 Improve remote device capability identification by switching to use UUIDs instead of class bits.
Change-Id: Ie60d1c579e40027c2174215c1989887a3250c9bc
Diffstat (limited to 'src')
-rw-r--r--src/com/android/settings/bluetooth/BluetoothEventRedirector.java11
-rw-r--r--src/com/android/settings/bluetooth/CachedBluetoothDevice.java91
-rw-r--r--src/com/android/settings/bluetooth/CachedBluetoothDeviceManager.java7
-rw-r--r--src/com/android/settings/bluetooth/LocalBluetoothProfileManager.java88
4 files changed, 154 insertions, 43 deletions
diff --git a/src/com/android/settings/bluetooth/BluetoothEventRedirector.java b/src/com/android/settings/bluetooth/BluetoothEventRedirector.java
index 1a373dd..9aae8b1 100644
--- a/src/com/android/settings/bluetooth/BluetoothEventRedirector.java
+++ b/src/com/android/settings/bluetooth/BluetoothEventRedirector.java
@@ -37,16 +37,13 @@ import com.android.settings.bluetooth.LocalBluetoothProfileManager.Profile;
*/
public class BluetoothEventRedirector {
private static final String TAG = "BluetoothEventRedirector";
- private static final boolean V = LocalBluetoothManager.V;
private LocalBluetoothManager mManager;
private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- if (V) {
- Log.v(TAG, "Received " + intent.getAction());
- }
+ Log.v(TAG, "Received " + intent.getAction());
String action = intent.getAction();
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
@@ -65,6 +62,8 @@ public class BluetoothEventRedirector {
short rssi = intent.getShortExtra(BluetoothDevice.EXTRA_RSSI, Short.MIN_VALUE);
BluetoothClass btClass = intent.getParcelableExtra(BluetoothDevice.EXTRA_CLASS);
String name = intent.getStringExtra(BluetoothDevice.EXTRA_NAME);
+ // TODO Pick up UUID. They should be available for 2.1 devices.
+ // Skip for now, there's a bluez problem and we are not getting uuids even for 2.1.
mManager.getCachedDeviceManager().onDeviceAppeared(device, rssi, btClass, name);
} else if (action.equals(BluetoothDevice.ACTION_DISAPPEARED)) {
@@ -107,6 +106,9 @@ public class BluetoothEventRedirector {
} else if (action.equals(BluetoothDevice.ACTION_CLASS_CHANGED)) {
mManager.getCachedDeviceManager().onBtClassChanged(device);
+ } else if (action.equals(BluetoothDevice.ACTION_UUID)) {
+ mManager.getCachedDeviceManager().onUuidChanged(device);
+
} else if (action.equals(BluetoothDevice.ACTION_PAIRING_CANCEL)) {
int errorMsg = R.string.bluetooth_pairing_error_message;
mManager.showError(device, R.string.bluetooth_error_title, errorMsg);
@@ -139,6 +141,7 @@ public class BluetoothEventRedirector {
filter.addAction(BluetoothA2dp.ACTION_SINK_STATE_CHANGED);
filter.addAction(BluetoothHeadset.ACTION_STATE_CHANGED);
filter.addAction(BluetoothDevice.ACTION_CLASS_CHANGED);
+ filter.addAction(BluetoothDevice.ACTION_UUID);
mManager.getContext().registerReceiver(mBroadcastReceiver, filter);
}
diff --git a/src/com/android/settings/bluetooth/CachedBluetoothDevice.java b/src/com/android/settings/bluetooth/CachedBluetoothDevice.java
index fdba11b..e70f85f 100644
--- a/src/com/android/settings/bluetooth/CachedBluetoothDevice.java
+++ b/src/com/android/settings/bluetooth/CachedBluetoothDevice.java
@@ -17,13 +17,15 @@
package com.android.settings.bluetooth;
import android.app.AlertDialog;
-import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
+import android.bluetooth.ParcelUuid;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Resources;
+import android.os.SystemClock;
import android.text.TextUtils;
import android.util.Log;
import android.view.ContextMenu;
@@ -50,6 +52,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
private static final String TAG = "CachedBluetoothDevice";
private static final boolean D = LocalBluetoothManager.D;
private static final boolean V = LocalBluetoothManager.V;
+ private static final boolean DEBUG = true; // STOPSHIP - disable before final rom
private static final int CONTEXT_ITEM_CONNECT = Menu.FIRST + 1;
private static final int CONTEXT_ITEM_DISCONNECT = Menu.FIRST + 2;
@@ -75,6 +78,17 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
*/
private boolean mIsConnectingErrorPossible;
+ /**
+ * Last time a bt profile auto-connect was attempted without any profiles or
+ * UUIDs. If an ACTION_UUID intent comes in within
+ * MAX_UUID_DELAY_FOR_AUTO_CONNECT milliseconds, we will try auto-connect
+ * again with the new UUIDs
+ */
+ private long mConnectAttemptedWithoutUuid;
+
+ // See mConnectAttemptedWithoutUuid
+ private static final long MAX_UUID_DELAY_FOR_AUTO_CONNECT = 5000;
+
// Max time to hold the work queue if we don't get or missed a response
// from the bt framework.
private static final long MAX_WAIT_TIME_FOR_FRAMEWORK = 25 * 1000;
@@ -361,6 +375,16 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
public void connect() {
if (!ensurePaired()) return;
+ // Try to initialize the profiles if there were not.
+ if (mProfiles.size() == 0) {
+ if (!updateProfiles()) {
+ // If UUIDs are not available yet, connect will be happen
+ // upon arrival of the ACTION_UUID intent.
+ mConnectAttemptedWithoutUuid = SystemClock.elapsedRealtime();
+ return;
+ }
+ }
+
// Reset the only-show-one-error-dialog tracking variable
mIsConnectingErrorPossible = true;
@@ -479,6 +503,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
private void fillData() {
fetchName();
fetchBtClass();
+ updateProfiles();
mVisible = false;
@@ -599,9 +624,47 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
*/
private void fetchBtClass() {
mBtClass = mDevice.getBluetoothClass();
- if (mBtClass != null) {
- LocalBluetoothProfileManager.fill(mBtClass, mProfiles);
+ }
+
+ private boolean updateProfiles() {
+ ParcelUuid[] uuids = mDevice.getUuids();
+ if (uuids == null) return false;
+
+ LocalBluetoothProfileManager.updateProfiles(uuids, mProfiles);
+
+ if (DEBUG) {
+ Log.e(TAG, "updating profiles for " + mDevice.getName());
+
+ boolean printUuids = true;
+ BluetoothClass bluetoothClass = mDevice.getBluetoothClass();
+
+ if (bluetoothClass.doesClassMatch(BluetoothClass.PROFILE_HEADSET) !=
+ mProfiles.contains(Profile.HEADSET)) {
+ Log.v(TAG, "headset classbits != uuid");
+ printUuids = true;
+ }
+
+ if (bluetoothClass.doesClassMatch(BluetoothClass.PROFILE_A2DP) !=
+ mProfiles.contains(Profile.A2DP)) {
+ Log.v(TAG, "a2dp classbits != uuid");
+ printUuids = true;
+ }
+
+ if (bluetoothClass.doesClassMatch(BluetoothClass.PROFILE_OPP) !=
+ mProfiles.contains(Profile.OPP)) {
+ Log.v(TAG, "opp classbits != uuid");
+ printUuids = true;
+ }
+
+ if (printUuids) {
+ Log.v(TAG, "Class: " + bluetoothClass.toString());
+ Log.v(TAG, "UUID:");
+ for (int i = 0; i < uuids.length; i++) {
+ Log.v(TAG, " " + uuids[i]);
+ }
+ }
}
+ return true;
}
/**
@@ -613,10 +676,30 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
dispatchAttributesChanged();
}
+ /**
+ * Refreshes the UI when framework alerts us of a UUID change.
+ */
+ public void onUuidChanged() {
+ updateProfiles();
+
+ if (DEBUG) Log.e(TAG, "onUuidChanged: Time since last connect w/ no uuid "
+ + (SystemClock.elapsedRealtime() - mConnectAttemptedWithoutUuid));
+
+ /*
+ * If a connect was attempted earlier without any UUID, we will do the
+ * connect now.
+ */
+ if (mProfiles.size() > 0
+ && (mConnectAttemptedWithoutUuid + MAX_UUID_DELAY_FOR_AUTO_CONNECT) > SystemClock
+ .elapsedRealtime()) {
+ connect();
+ }
+ dispatchAttributesChanged();
+ }
+
public void setBtClass(BluetoothClass btClass) {
if (btClass != null && mBtClass != btClass) {
mBtClass = btClass;
- LocalBluetoothProfileManager.fill(mBtClass, mProfiles);
dispatchAttributesChanged();
}
}
diff --git a/src/com/android/settings/bluetooth/CachedBluetoothDeviceManager.java b/src/com/android/settings/bluetooth/CachedBluetoothDeviceManager.java
index 046cd76..b7cea23 100644
--- a/src/com/android/settings/bluetooth/CachedBluetoothDeviceManager.java
+++ b/src/com/android/settings/bluetooth/CachedBluetoothDeviceManager.java
@@ -257,4 +257,11 @@ public class CachedBluetoothDeviceManager {
cachedDevice.refreshBtClass();
}
}
+
+ public synchronized void onUuidChanged(BluetoothDevice device) {
+ CachedBluetoothDevice cachedDevice = findDevice(device);
+ if (cachedDevice != null) {
+ cachedDevice.onUuidChanged();
+ }
+ }
}
diff --git a/src/com/android/settings/bluetooth/LocalBluetoothProfileManager.java b/src/com/android/settings/bluetooth/LocalBluetoothProfileManager.java
index a59d229..2ea1fe7 100644
--- a/src/com/android/settings/bluetooth/LocalBluetoothProfileManager.java
+++ b/src/com/android/settings/bluetooth/LocalBluetoothProfileManager.java
@@ -18,10 +18,10 @@ package com.android.settings.bluetooth;
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothHeadset;
+import android.bluetooth.BluetoothUuid;
+import android.bluetooth.ParcelUuid;
import android.os.Handler;
-import android.text.TextUtils;
import com.android.settings.R;
@@ -35,27 +35,42 @@ import java.util.Set;
* functionality related to a profile.
*/
public abstract class LocalBluetoothProfileManager {
+ private static final String TAG = "LocalBluetoothProfileManager";
+
+ private static final ParcelUuid[] HEADSET_PROFILE_UUIDS = new ParcelUuid[] {
+ BluetoothUuid.HSP,
+ BluetoothUuid.Handsfree,
+ };
+
+ private static final ParcelUuid[] A2DP_PROFILE_UUIDS = new ParcelUuid[] {
+ BluetoothUuid.AudioSink,
+ BluetoothUuid.AdvAudioDist,
+ };
+
+ private static final ParcelUuid[] OPP_PROFILE_UUIDS = new ParcelUuid[] {
+ BluetoothUuid.ObexObjectPush
+ };
// TODO: close profiles when we're shutting down
private static Map<Profile, LocalBluetoothProfileManager> sProfileMap =
- new HashMap<Profile, LocalBluetoothProfileManager>();
-
+ new HashMap<Profile, LocalBluetoothProfileManager>();
+
protected LocalBluetoothManager mLocalManager;
-
+
public static LocalBluetoothProfileManager getProfileManager(LocalBluetoothManager localManager,
Profile profile) {
-
+
LocalBluetoothProfileManager profileManager;
-
+
synchronized (sProfileMap) {
profileManager = sProfileMap.get(profile);
-
+
if (profileManager == null) {
switch (profile) {
case A2DP:
profileManager = new A2dpProfileManager(localManager);
break;
-
+
case HEADSET:
profileManager = new HeadsetProfileManager(localManager);
break;
@@ -64,35 +79,38 @@ public abstract class LocalBluetoothProfileManager {
profileManager = new OppProfileManager(localManager);
break;
}
-
- sProfileMap.put(profile, profileManager);
+
+ sProfileMap.put(profile, profileManager);
}
}
-
+
return profileManager;
}
/**
* Temporary method to fill profiles based on a device's class.
- *
+ *
* NOTE: This list happens to define the connection order. We should put this logic in a more
* well known place when this method is no longer temporary.
- *
- * @param btClass The class
+ * @param uuids of the remote device
* @param profiles The list of profiles to fill
*/
- public static void fill(BluetoothClass btClass, List<Profile> profiles) {
+ public static void updateProfiles(ParcelUuid[] uuids, List<Profile> profiles) {
profiles.clear();
- if (btClass.doesClassMatch(BluetoothClass.PROFILE_HEADSET)) {
+ if (uuids == null) {
+ return;
+ }
+
+ if (BluetoothUuid.containsAnyUuid(uuids, HEADSET_PROFILE_UUIDS)) {
profiles.add(Profile.HEADSET);
}
- if (btClass.doesClassMatch(BluetoothClass.PROFILE_A2DP)) {
+ if (BluetoothUuid.containsAnyUuid(uuids, A2DP_PROFILE_UUIDS)) {
profiles.add(Profile.A2DP);
}
- if (btClass.doesClassMatch(BluetoothClass.PROFILE_OPP)) {
+ if (BluetoothUuid.containsAnyUuid(uuids, OPP_PROFILE_UUIDS)) {
profiles.add(Profile.OPP);
}
}
@@ -100,17 +118,17 @@ public abstract class LocalBluetoothProfileManager {
protected LocalBluetoothProfileManager(LocalBluetoothManager localManager) {
mLocalManager = localManager;
}
-
+
public abstract boolean connect(BluetoothDevice device);
-
+
public abstract boolean disconnect(BluetoothDevice device);
-
+
public abstract int getConnectionStatus(BluetoothDevice device);
public abstract int getSummary(BluetoothDevice device);
public abstract int convertState(int a2dpState);
-
+
public abstract boolean isPreferred(BluetoothDevice device);
public abstract void setPreferred(BluetoothDevice device, boolean preferred);
@@ -118,26 +136,26 @@ public abstract class LocalBluetoothProfileManager {
public boolean isConnected(BluetoothDevice device) {
return SettingsBtStatus.isConnectionStatusConnected(getConnectionStatus(device));
}
-
+
// TODO: int instead of enum
public enum Profile {
HEADSET(R.string.bluetooth_profile_headset),
A2DP(R.string.bluetooth_profile_a2dp),
OPP(R.string.bluetooth_profile_opp);
-
+
public final int localizedString;
-
+
private Profile(int localizedString) {
this.localizedString = localizedString;
}
}
/**
- * A2dpProfileManager is an abstraction for the {@link BluetoothA2dp} service.
+ * A2dpProfileManager is an abstraction for the {@link BluetoothA2dp} service.
*/
private static class A2dpProfileManager extends LocalBluetoothProfileManager {
private BluetoothA2dp mService;
-
+
public A2dpProfileManager(LocalBluetoothManager localManager) {
super(localManager);
mService = new BluetoothA2dp(localManager.getContext());
@@ -158,12 +176,12 @@ public abstract class LocalBluetoothProfileManager {
public boolean disconnect(BluetoothDevice device) {
return mService.disconnectSink(device);
}
-
+
@Override
public int getConnectionStatus(BluetoothDevice device) {
return convertState(mService.getSinkState(device));
}
-
+
@Override
public int getSummary(BluetoothDevice device) {
int connectionStatus = getConnectionStatus(device);
@@ -204,15 +222,15 @@ public abstract class LocalBluetoothProfileManager {
}
}
}
-
+
/**
- * HeadsetProfileManager is an abstraction for the {@link BluetoothHeadset} service.
+ * HeadsetProfileManager is an abstraction for the {@link BluetoothHeadset} service.
*/
private static class HeadsetProfileManager extends LocalBluetoothProfileManager
implements BluetoothHeadset.ServiceListener {
private BluetoothHeadset mService;
private Handler mUiHandler = new Handler();
-
+
public HeadsetProfileManager(LocalBluetoothManager localManager) {
super(localManager);
mService = new BluetoothHeadset(localManager.getContext(), this);
@@ -262,11 +280,11 @@ public abstract class LocalBluetoothProfileManager {
? convertState(mService.getState())
: SettingsBtStatus.CONNECTION_STATUS_DISCONNECTED;
}
-
+
@Override
public int getSummary(BluetoothDevice device) {
int connectionStatus = getConnectionStatus(device);
-
+
if (SettingsBtStatus.isConnectionStatusConnected(connectionStatus)) {
return R.string.bluetooth_headset_profile_summary_connected;
} else {