Implement Bluetooth device picker

Add Bluetooth device picker in Settings
- add resource to support device picker
- show different UI accroding to start Intent
- add OPP profile manager
This commit is contained in:
Yue Lixin
2009-07-09 16:48:52 +08:00
committed by Nick Pelly
parent 3b94f09756
commit a41e2f94b7
7 changed files with 273 additions and 31 deletions

View File

@@ -105,7 +105,9 @@ public class BluetoothDevicePreference extends Preference implements CachedBluet
@Override
protected void onBindView(View view) {
// Disable this view if the bluetooth enable/disable preference view is off
setDependency("bt_checkbox");
if (null != findPreferenceInHierarchy("bt_checkbox")){
setDependency("bt_checkbox");
}
super.onBindView(view);

View File

@@ -18,12 +18,15 @@ package com.android.settings.bluetooth;
import com.android.settings.ProgressCategory;
import com.android.settings.R;
import com.android.settings.bluetooth.LocalBluetoothProfileManager.Profile;
import java.util.List;
import java.util.WeakHashMap;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothIntent;
import android.bluetooth.BluetoothError;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -39,6 +42,7 @@ import android.view.MenuItem;
import android.view.View;
import android.view.ContextMenu.ContextMenuInfo;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.util.Log;
/**
* BluetoothSettings is the Settings screen for Bluetooth configuration and
@@ -57,6 +61,15 @@ public class BluetoothSettings extends PreferenceActivity
private static final String KEY_BT_NAME = "bt_name";
private static final String KEY_BT_SCAN = "bt_scan";
private static final int SCREEN_TYPE_SETTINGS = 0;
private static final int SCREEN_TYPE_DEVICEPICKER = 1;
private int mScreenType;
private int mFilterType;
private boolean mNeedAuth;
private String mLaunchPackage;
private String mLaunchClass;
private LocalBluetoothManager mLocalManager;
private BluetoothEnabler mEnabler;
@@ -73,7 +86,19 @@ public class BluetoothSettings extends PreferenceActivity
@Override
public void onReceive(Context context, Intent intent) {
// TODO: put this in callback instead of receiving
onBluetoothStateChanged(mLocalManager.getBluetoothState());
if (intent.getAction().equals(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION)) {
onBluetoothStateChanged(mLocalManager.getBluetoothState());
} else if (intent.getAction().equals(BluetoothIntent.BOND_STATE_CHANGED_ACTION)
&& mScreenType == SCREEN_TYPE_DEVICEPICKER) {
int bondState = intent
.getIntExtra(BluetoothIntent.BOND_STATE, BluetoothError.ERROR);
if (bondState == BluetoothDevice.BOND_BONDED) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothIntent.DEVICE);
sendDevicePickedIntent(device);
finish();
}
}
}
};
@@ -84,17 +109,44 @@ public class BluetoothSettings extends PreferenceActivity
mLocalManager = LocalBluetoothManager.getInstance(this);
if (mLocalManager == null) finish();
addPreferencesFromResource(R.xml.bluetooth_settings);
// Note:
// If an application wish to show the BT device list, it can send an
// intent to Settings application with below extra data:
// -DEVICE_PICKER_FILTER_TYPE: the type of BT devices that want to show.
// -DEVICE_PICKER_LAUNCH_PACKAGE: the package which the application belongs to.
// -DEVICE_PICKER_LAUNCH_CLASS: the class which will receive user's selected
// result from the BT list.
// -DEVICE_PICKER_NEED_AUTH: to show if bonding procedure needed.
mEnabler = new BluetoothEnabler(
this,
(CheckBoxPreference) findPreference(KEY_BT_CHECKBOX));
mFilterType = BluetoothDevice.DEVICE_PICKER_FILTER_TYPE_ALL;
Intent intent = getIntent();
String action = intent.getAction();
mDiscoverableEnabler = new BluetoothDiscoverableEnabler(
this,
(CheckBoxPreference) findPreference(KEY_BT_DISCOVERABLE));
if (action.equals(BluetoothIntent.DEVICE_PICKER_DEVICE_PICKER)) {
mScreenType = SCREEN_TYPE_DEVICEPICKER;
mNeedAuth = intent.getBooleanExtra(BluetoothIntent.DEVICE_PICKER_NEED_AUTH, false);
mFilterType = intent.getIntExtra(BluetoothIntent.DEVICE_PICKER_FILTER_TYPE,
BluetoothDevice.DEVICE_PICKER_FILTER_TYPE_ALL);
mLaunchPackage = intent.getStringExtra(BluetoothIntent.DEVICE_PICKER_LAUNCH_PACKAGE);
mLaunchClass = intent.getStringExtra(BluetoothIntent.DEVICE_PICKER_LAUNCH_CLASS);
mNamePreference = (BluetoothNamePreference) findPreference(KEY_BT_NAME);
setTitle(getString(R.string.device_picker));
addPreferencesFromResource(R.xml.device_picker);
} else {
addPreferencesFromResource(R.xml.bluetooth_settings);
mEnabler = new BluetoothEnabler(
this,
(CheckBoxPreference) findPreference(KEY_BT_CHECKBOX));
mDiscoverableEnabler = new BluetoothDiscoverableEnabler(
this,
(CheckBoxPreference) findPreference(KEY_BT_DISCOVERABLE));
mNamePreference = (BluetoothNamePreference) findPreference(KEY_BT_NAME);
mDeviceList = (ProgressCategory) findPreference(KEY_BT_DEVICE_LIST);
}
mDeviceList = (ProgressCategory) findPreference(KEY_BT_DEVICE_LIST);
@@ -111,17 +163,21 @@ public class BluetoothSettings extends PreferenceActivity
mDeviceList.removeAll();
addDevices();
mEnabler.resume();
mDiscoverableEnabler.resume();
mNamePreference.resume();
if (mScreenType == SCREEN_TYPE_SETTINGS) {
mEnabler.resume();
mDiscoverableEnabler.resume();
mNamePreference.resume();
}
mLocalManager.registerCallback(this);
mDeviceList.setProgress(mLocalManager.getBluetoothAdapter().isDiscovering());
mLocalManager.startScanning(false);
registerReceiver(mReceiver,
new IntentFilter(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION));
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION);
intentFilter.addAction(BluetoothIntent.BOND_STATE_CHANGED_ACTION);
registerReceiver(mReceiver, intentFilter);
mLocalManager.setForegroundActivity(this);
}
@@ -134,9 +190,11 @@ public class BluetoothSettings extends PreferenceActivity
unregisterReceiver(mReceiver);
mLocalManager.unregisterCallback(this);
mNamePreference.pause();
mDiscoverableEnabler.pause();
mEnabler.pause();
if (mScreenType == SCREEN_TYPE_SETTINGS) {
mNamePreference.pause();
mDiscoverableEnabler.pause();
mEnabler.pause();
}
}
private void addDevices() {
@@ -184,8 +242,20 @@ public class BluetoothSettings extends PreferenceActivity
}
if (preference instanceof BluetoothDevicePreference) {
BluetoothDevicePreference btPreference = (BluetoothDevicePreference) preference;
btPreference.getCachedDevice().onClicked();
BluetoothDevicePreference btPreference = (BluetoothDevicePreference)preference;
if (mScreenType == SCREEN_TYPE_SETTINGS) {
btPreference.getCachedDevice().onClicked();
} else if (mScreenType == SCREEN_TYPE_DEVICEPICKER) {
CachedBluetoothDevice device = btPreference.getCachedDevice();
if ((device.getBondState() == BluetoothDevice.BOND_BONDED) || (mNeedAuth == false)) {
BluetoothDevice btAddress = btPreference.getCachedDevice().getDevice();
sendDevicePickedIntent(btAddress);
finish();
} else {
btPreference.getCachedDevice().onClicked();
}
}
return true;
}
@@ -195,6 +265,10 @@ public class BluetoothSettings extends PreferenceActivity
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
//For device picker, disable Context Menu
if (mScreenType != SCREEN_TYPE_SETTINGS) {
return;
}
CachedBluetoothDevice cachedDevice = getDeviceFromMenuInfo(menuInfo);
if (cachedDevice == null) return;
@@ -231,8 +305,19 @@ public class BluetoothSettings extends PreferenceActivity
throw new IllegalStateException("Got onDeviceAdded, but cachedDevice already exists");
}
createDevicePreference(cachedDevice);
}
List<Profile> profiles = cachedDevice.getProfiles();
if (mFilterType == BluetoothDevice.DEVICE_PICKER_FILTER_TYPE_TRANSFER){
if(profiles.contains(Profile.OPP)){
createDevicePreference(cachedDevice);
}
} else if (mFilterType == BluetoothDevice.DEVICE_PICKER_FILTER_TYPE_AUDIO) {
if((profiles.contains(Profile.A2DP)) || (profiles.contains(Profile.HEADSET))){
createDevicePreference(cachedDevice);
}
} else {
createDevicePreference(cachedDevice);
}
}
private void createDevicePreference(CachedBluetoothDevice cachedDevice) {
BluetoothDevicePreference preference = new BluetoothDevicePreference(this, cachedDevice);
@@ -260,4 +345,13 @@ public class BluetoothSettings extends PreferenceActivity
mDeviceList.setProgress(false);
}
}
private void sendDevicePickedIntent(BluetoothDevice device) {
Intent intent = new Intent(BluetoothIntent.DEVICE_PICKER_DEVICE_SELECTED);
if (mLaunchPackage != null && mLaunchClass != null) {
intent.setClassName(mLaunchPackage, mLaunchClass);
}
intent.putExtra(BluetoothIntent.DEVICE, device);
sendBroadcast(intent);
}
}

View File

@@ -29,6 +29,8 @@ import android.preference.PreferenceGroup;
import android.text.TextUtils;
import android.util.Log;
import java.util.List;
/**
* ConnectSpecificProfilesActivity presents the user with all of the profiles
* for a particular device, and allows him to choose which should be connected
@@ -43,7 +45,10 @@ public class ConnectSpecificProfilesActivity extends PreferenceActivity
private static final String KEY_PROFILE_CONTAINER = "profile_container";
public static final String EXTRA_DEVICE = "device";
public static final String CLASS_NAME_OPP_PROFILE_MANAGER =
"com.android.settings.bluetooth.LocalBluetoothProfileManager$OppProfileManager";
private LocalBluetoothManager mManager;
private CachedBluetoothDevice mCachedDevice;
@@ -145,6 +150,19 @@ public class ConnectSpecificProfilesActivity extends PreferenceActivity
pref.setPersistent(false);
pref.setOnPreferenceChangeListener(this);
LocalBluetoothProfileManager profileManager = LocalBluetoothProfileManager
.getProfileManager(mManager, profile);
/**
* Gray out checkbox while connecting and disconnecting or this is OPP
* profile
*/
if (profileManager.getClass().getName().equals(CLASS_NAME_OPP_PROFILE_MANAGER)) {
pref.setEnabled(false);
} else {
pref.setEnabled(!mCachedDevice.isBusy());
}
refreshProfilePreference(pref, profile);
return pref;
@@ -221,6 +239,12 @@ public class ConnectSpecificProfilesActivity extends PreferenceActivity
/* Gray out checkbox while connecting and disconnecting */
mOnlineModePreference.setEnabled(!mCachedDevice.isBusy());
List<Profile> profiles = mCachedDevice.getProfiles();
if ((profiles.size() == 1) && (profiles.get(0).name().equals("OPP"))) {
Log.w(TAG, "there is only one profile: Opp, disable the connect button.");
mOnlineModePreference.setEnabled(false);
}
/**
* If the device is online, show status. Otherwise, show a summary that
* describes what the checkbox does.
@@ -249,9 +273,16 @@ public class ConnectSpecificProfilesActivity extends PreferenceActivity
int connectionStatus = profileManager.getConnectionStatus(device);
/* Gray out checkbox while connecting and disconnecting */
profilePref.setEnabled(!mCachedDevice.isBusy());
/*
* Gray out checkbox while connecting and disconnecting or this is OPP
* profile
*/
if (profileManager.getClass().getName().equals(CLASS_NAME_OPP_PROFILE_MANAGER)) {
Log.w(TAG, "this is Opp profile");
profilePref.setEnabled(false);
} else {
profilePref.setEnabled(!mCachedDevice.isBusy());
}
profilePref.setSummary(getProfileSummary(profileManager, profile, device,
connectionStatus, mOnlineMode));
@@ -291,6 +322,8 @@ public class ConnectSpecificProfilesActivity extends PreferenceActivity
return R.string.bluetooth_a2dp_profile_summary_use_for;
case HEADSET:
return R.string.bluetooth_headset_profile_summary_use_for;
case OPP:
return R.string.bluetooth_opp_profile_summary_use_for;
default:
return 0;
}

View File

@@ -18,6 +18,7 @@ package com.android.settings.bluetooth;
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothError;
import android.bluetooth.BluetoothHeadset;
import android.os.Handler;
@@ -59,6 +60,10 @@ public abstract class LocalBluetoothProfileManager {
case HEADSET:
profileManager = new HeadsetProfileManager(localManager);
break;
case OPP:
profileManager = new OppProfileManager(localManager);
break;
}
sProfileMap.put(profile, profileManager);
@@ -80,13 +85,17 @@ public abstract class LocalBluetoothProfileManager {
public static void fill(int btClass, List<Profile> profiles) {
profiles.clear();
if (BluetoothHeadset.doesClassMatch(btClass)) {
if (BluetoothClass.doesClassMatch(btClass, BluetoothClass.PROFILE_HEADSET)) {
profiles.add(Profile.HEADSET);
}
if (BluetoothA2dp.doesClassMatchSink(btClass)) {
if (BluetoothClass.doesClassMatch(btClass, BluetoothClass.PROFILE_A2DP)) {
profiles.add(Profile.A2DP);
}
if (BluetoothClass.doesClassMatch(btClass, BluetoothClass.PROFILE_OPP)) {
profiles.add(Profile.OPP);
}
}
protected LocalBluetoothProfileManager(LocalBluetoothManager localManager) {
@@ -114,7 +123,8 @@ public abstract class LocalBluetoothProfileManager {
// TODO: int instead of enum
public enum Profile {
HEADSET(R.string.bluetooth_profile_headset),
A2DP(R.string.bluetooth_profile_a2dp);
A2DP(R.string.bluetooth_profile_a2dp),
OPP(R.string.bluetooth_profile_opp);
public final int localizedString;
@@ -291,4 +301,63 @@ public abstract class LocalBluetoothProfileManager {
}
}
}
/**
* OppProfileManager
*/
private static class OppProfileManager extends LocalBluetoothProfileManager {
public OppProfileManager(LocalBluetoothManager localManager) {
super(localManager);
}
@Override
public int connect(BluetoothDevice device) {
return -1;
}
@Override
public int disconnect(BluetoothDevice device) {
return -1;
}
@Override
public int getConnectionStatus(BluetoothDevice device) {
return -1;
}
@Override
public int getSummary(BluetoothDevice device) {
int connectionStatus = getConnectionStatus(device);
if (SettingsBtStatus.isConnectionStatusConnected(connectionStatus)) {
return R.string.bluetooth_opp_profile_summary_connected;
} else {
return R.string.bluetooth_opp_profile_summary_not_connected;
}
}
@Override
public boolean isPreferred(BluetoothDevice device) {
return false;
}
@Override
public void setPreferred(BluetoothDevice device, boolean preferred) {
}
@Override
public int convertState(int oppState) {
switch (oppState) {
case 0:
return SettingsBtStatus.CONNECTION_STATUS_CONNECTED;
case 1:
return SettingsBtStatus.CONNECTION_STATUS_CONNECTING;
case 2:
return SettingsBtStatus.CONNECTION_STATUS_DISCONNECTED;
default:
return SettingsBtStatus.CONNECTION_STATUS_UNKNOWN;
}
}
}
}