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

@@ -125,6 +125,10 @@
<category android:name="com.android.settings.SHORTCUT" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter>
<action android:name="android.bluetooth.intent.action.DEVICE_PICKER" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity android:name=".vpn.VpnSettings"

View File

@@ -215,6 +215,8 @@
<!-- Notification message when a Bluetooth device wants to pair with us -->
<string name="bluetooth_notif_message">Select to pair with\u0020</string>
<!-- Strings for BluetoothDevicePicker -->
<string name="device_picker">Bluetooth device picker</string>
<!-- Do not translate. Used for diagnostic screens, precise translation is not necessary -->
<string name="bluetooth_scan_text">Empty button\u2026</string>
@@ -568,6 +570,8 @@
<string name="bluetooth_profile_a2dp">Media</string>
<!-- Bluetooth settings. The user-visible string that is used whenever referring to the headset or handsfree profile. -->
<string name="bluetooth_profile_headset">Phone</string>
<!-- Bluetooth settings. The user-visible string that is used whenever referring to the OPP profile. -->
<string name="bluetooth_profile_opp">Transfer</string>
<!-- Bluetooth settings. The summary string when a device is connected to the A2DP profile. -->
<string name="bluetooth_summary_connected_to_a2dp">Connected to media audio</string>
@@ -588,11 +592,17 @@
<string name="bluetooth_a2dp_profile_summary_connected">Connected to media audio</string>
<!-- Bluetooth settings. Connection options screen. The summary for the headset checkbox preference when headset is connected. -->
<string name="bluetooth_headset_profile_summary_connected">Connected to phone audio</string>
<!-- Bluetooth settings. Connection options screen. The summary for the OPP checkbox preference when OPP is connected. -->
<string name="bluetooth_opp_profile_summary_connected">Connected to file transfer server</string>
<!-- Bluetooth settings. Connection options screen. The summary for the OPP checkbox preference when OPP is not connected. -->
<string name="bluetooth_opp_profile_summary_not_connected">Not connected to file transfer server</string>
<!-- Bluetooth settings. Connection options screen. The summary for the A2DP checkbox preference that describes how checking it will set the A2DP profile as preferred. -->
<string name="bluetooth_a2dp_profile_summary_use_for">Use for media audio</string>
<!-- Bluetooth settings. Connection options screen. The summary for the headset checkbox preference that describes how checking it will set the headset profile as preferred. -->
<string name="bluetooth_headset_profile_summary_use_for">Use for phone audio</string>
<!-- Bluetooth settings. Connection options screen. The summary for the OPP checkbox preference that describes how checking it will set the OPP profile as preferred. -->
<string name="bluetooth_opp_profile_summary_use_for">Use for file transfer</string>
<!-- Wi-Fi settings -->
<!-- Used in the 2nd-level settings screen to turn on Wi-Fi -->

30
res/xml/device_picker.xml Normal file
View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2007 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android">
<Preference
android:key="bt_scan"
android:title="@string/bluetooth_preference_scan_title" />
<com.android.settings.ProgressCategory
android:key="bt_device_list"
android:title="@string/bluetooth_devices"
android:orderingFromXml="false" />
</PreferenceScreen>

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;
}
}
}
}