diff options
author | Michael Chan <mchan@android.com> | 2009-09-20 18:18:27 -0700 |
---|---|---|
committer | Michael Chan <mchan@android.com> | 2009-09-22 15:37:14 -0700 |
commit | 2aef1f3c814b1f8aa00aeefff35caf293c738702 (patch) | |
tree | 228cfc552861d4b8a349d485da4de50fa4387bc1 /src | |
parent | d459bebd89756a8b735feb6f27bd864b0427feb7 (diff) | |
download | packages_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')
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 { |