Improve Bluetooth tethering UI usability.
- Updated hint text for BT tethering checkbox to "[Sharing|not sharing] this [tablet|phone]'s mobile data connection". - Show correct hint text when user enters tethering screen. - Show correct status after user enables tethering when Bluetooth is off. When BluetoothPan.setBluetoothTethering(true) is called with BT off, BluetoothPanProfileHandler will add a broadcast receiver to enable tethering after BT turns on. This happens too late to show the correct status when TetherSettings gets the adapter state changed event, so set a flag (mBluetoothEnableForTether) instead, and call setBluetoothTethering ourselves after the state changes to ON. Also, clear the flag if the adapter state changes to OFF or ERROR. - Show correct status when user enables tethering, then disables Bluetooth, then returns to the tethering screen. Previously it would show Bluetooth tethering enabled, even though adapter state was OFF. - Show the number of connected devices in tethering preference screen. - Distinguish between PANU and NAP in device profiles screen, and show appropriate text to clarify the direction of tethering. - Remove profiles from device profiles list when the device removes the UUID (e.g. Mac OS X turning NAP on/off) and after a NAP disconnection when the remote device only supports PANU. Bug: 3414575 Change-Id: I2c0830876d5b9bddb293e57c4d3ca74f105911b8
This commit is contained in:
@@ -950,16 +950,20 @@
|
|||||||
<!-- Bluetooth settings. The user-visible string that is used whenever referring to the HID profile. -->
|
<!-- Bluetooth settings. The user-visible string that is used whenever referring to the HID profile. -->
|
||||||
<string name="bluetooth_profile_hid">Input Device</string>
|
<string name="bluetooth_profile_hid">Input Device</string>
|
||||||
<!-- Bluetooth settings. The user-visible string that is used whenever referring to the PAN profile. [CHAR LIMIT=25]-->
|
<!-- Bluetooth settings. The user-visible string that is used whenever referring to the PAN profile. [CHAR LIMIT=25]-->
|
||||||
<string name="bluetooth_profile_pan">Tethering</string>
|
<string name="bluetooth_profile_pan">Internet access</string>
|
||||||
|
|
||||||
<!-- Bluetooth settings. Message for disconnecting from the A2DP profile. -->
|
<!-- Bluetooth settings. Message for disconnecting from the A2DP profile. [CHAR LIMIT=80] -->
|
||||||
<string name="bluetooth_disconnect_a2dp_profile"><xliff:g id="device_name">%1$s</xliff:g> will be disconnected from media audio.</string>
|
<string name="bluetooth_disconnect_a2dp_profile"><xliff:g id="device_name">%1$s</xliff:g> will be disconnected from media audio.</string>
|
||||||
<!-- Bluetooth settings. Message for disconnecting from the headset profile. -->
|
<!-- Bluetooth settings. Message for disconnecting from the headset profile. [CHAR LIMIT=80] -->
|
||||||
<string name="bluetooth_disconnect_headset_profile"><xliff:g id="device_name">%1$s</xliff:g> will be disconnected from handsfree audio.</string>
|
<string name="bluetooth_disconnect_headset_profile"><xliff:g id="device_name">%1$s</xliff:g> will be disconnected from handsfree audio.</string>
|
||||||
<!-- Bluetooth settings. Message for disconnecting from the HID profile. -->
|
<!-- Bluetooth settings. Message for disconnecting from the HID profile. [CHAR LIMIT=80] -->
|
||||||
<string name="bluetooth_disconnect_hid_profile"><xliff:g id="device_name">%1$s</xliff:g> will be disconnected from input device.</string>
|
<string name="bluetooth_disconnect_hid_profile"><xliff:g id="device_name">%1$s</xliff:g> will be disconnected from input device.</string>
|
||||||
<!-- Bluetooth settings. Message for disconnecting from the PAN profile. -->
|
<!-- Bluetooth settings. Message for disconnecting from the PAN profile (user role). [CHAR LIMIT=80] -->
|
||||||
<string name="bluetooth_disconnect_pan_profile"><xliff:g id="device_name">%1$s</xliff:g> will be disconnected from tethering.</string>
|
<string name="bluetooth_disconnect_pan_user_profile">Internet access via <xliff:g id="device_name">%1$s</xliff:g> will be disconnected.</string>
|
||||||
|
<!-- Bluetooth settings. Message for disconnecting from the PAN profile (NAP role). [CHAR LIMIT=80] -->
|
||||||
|
<string name="bluetooth_disconnect_pan_nap_profile" product="tablet"><xliff:g id="device_name">%1$s</xliff:g> will be disconnected from sharing this tablet\'s Internet connection.</string>
|
||||||
|
<!-- Bluetooth settings. Message for disconnecting from the PAN profile (NAP role). [CHAR LIMIT=80] -->
|
||||||
|
<string name="bluetooth_disconnect_pan_nap_profile" product="default"><xliff:g id="device_name">%1$s</xliff:g> will be disconnected from sharing this phone\'s Internet connection.</string>
|
||||||
|
|
||||||
<!-- Bluetooth settings. Connection options screen. The title of the screen. -->
|
<!-- Bluetooth settings. Connection options screen. The title of the screen. -->
|
||||||
<string name="bluetooth_device_advanced_title"><xliff:g id="device_name">%1$s</xliff:g> options</string>
|
<string name="bluetooth_device_advanced_title"><xliff:g id="device_name">%1$s</xliff:g> options</string>
|
||||||
@@ -985,8 +989,10 @@
|
|||||||
<string name="bluetooth_opp_profile_summary_not_connected">Not connected to file transfer server</string>
|
<string name="bluetooth_opp_profile_summary_not_connected">Not connected to file transfer server</string>
|
||||||
<!-- Bluetooth settings. Connection options screen. The summary for the HID checkbox preference when HID is connected. -->
|
<!-- Bluetooth settings. Connection options screen. The summary for the HID checkbox preference when HID is connected. -->
|
||||||
<string name="bluetooth_hid_profile_summary_connected">Connected to input device</string>
|
<string name="bluetooth_hid_profile_summary_connected">Connected to input device</string>
|
||||||
<!-- Bluetooth settings. Connection options screen. The summary for the PAN checkbox preference when PAN is connected. [CHAR LIMIT=25]-->
|
<!-- Bluetooth settings. Connection options screen. The summary for the checkbox preference when PAN is connected (user role). [CHAR LIMIT=25]-->
|
||||||
<string name="bluetooth_pan_profile_summary_connected">Tethered</string>
|
<string name="bluetooth_pan_user_profile_summary_connected">Connected to device for Internet access</string>
|
||||||
|
<!-- Bluetooth settings. Connection options screen. The summary for the checkbox preference when PAN is connected (NAP role). [CHAR LIMIT=25]-->
|
||||||
|
<string name="bluetooth_pan_nap_profile_summary_connected">Sharing local Internet connection with device</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. -->
|
<!-- 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>
|
<string name="bluetooth_a2dp_profile_summary_use_for">Use for media audio</string>
|
||||||
@@ -1863,11 +1869,21 @@
|
|||||||
<!-- Label for bluetooth tether checkbox [CHAR LIMIT=25]-->
|
<!-- Label for bluetooth tether checkbox [CHAR LIMIT=25]-->
|
||||||
<string name="bluetooth_tether_checkbox_text">Bluetooth tethering</string>
|
<string name="bluetooth_tether_checkbox_text">Bluetooth tethering</string>
|
||||||
<!-- Bluetooth available subtext - shown when Bluetooth tethering is turned on but it is not currently tethered to any devices [CHAR LIMIT=50]-->
|
<!-- Bluetooth available subtext - shown when Bluetooth tethering is turned on but it is not currently tethered to any devices [CHAR LIMIT=50]-->
|
||||||
<string name="bluetooth_tethering_available_subtext">Bluetooth tethering on, but not connected</string>
|
<string name="bluetooth_tethering_available_subtext" product="tablet">Sharing this tablet\'s Internet connection</string>
|
||||||
<!-- Bluetooth connected subtext - shown when a device is tethered over Bluetooth [CHAR LIMIT=50]-->
|
<!-- Bluetooth available subtext - shown when Bluetooth tethering is turned on but it is not currently tethered to any devices [CHAR LIMIT=50]-->
|
||||||
<string name="bluetooth_tethering_connected_subtext">Bluetooth tethering on and connected</string>
|
<string name="bluetooth_tethering_available_subtext" product="default">Sharing this phone\'s Internet connection</string>
|
||||||
|
<!-- Bluetooth connected subtext - shown when a device is tethered over Bluetooth [CHAR LIMIT=60]-->
|
||||||
|
<string name="bluetooth_tethering_device_connected_subtext" product="tablet">Sharing this tablet\'s Internet connection to 1 device</string>
|
||||||
|
<!-- Bluetooth connected subtext - shown when a device is tethered over Bluetooth [CHAR LIMIT=60]-->
|
||||||
|
<string name="bluetooth_tethering_device_connected_subtext" product="default">Sharing this phone\'s Internet connection to 1 device</string>
|
||||||
|
<!-- Bluetooth connected subtext - shown when multiple devices are tethered over Bluetooth [CHAR LIMIT=60]-->
|
||||||
|
<string name="bluetooth_tethering_devices_connected_subtext" product="tablet">Sharing this tablet\'s Internet connection to <xliff:g id="connectedDeviceCount">%1$d</xliff:g> devices</string>
|
||||||
|
<!-- Bluetooth connected subtext - shown when multiple devices are tethered over Bluetooth [CHAR LIMIT=60]-->
|
||||||
|
<string name="bluetooth_tethering_devices_connected_subtext" product="default">Sharing this phone\'s Internet connection to <xliff:g id="connectedDeviceCount">%1$d</xliff:g> devices</string>
|
||||||
<!-- Bluetooth tethering off subtext - shown when Bluetooth Tethering is turned off [CHAR LIMIT=50]-->
|
<!-- Bluetooth tethering off subtext - shown when Bluetooth Tethering is turned off [CHAR LIMIT=50]-->
|
||||||
<string name="bluetooth_tethering_off_subtext">Bluetooth tethering off</string>
|
<string name="bluetooth_tethering_off_subtext" product="tablet">Not sharing this tablet\'s Internet connection</string>
|
||||||
|
<!-- Bluetooth tethering off subtext - shown when Bluetooth Tethering is turned off [CHAR LIMIT=50]-->
|
||||||
|
<string name="bluetooth_tethering_off_subtext" product="default">Not sharing this phone\'s Internet connection</string>
|
||||||
<!-- Bluetooth errored subtext - shown when Bluetooth is broken for some reason [CHAR LIMIT=50]-->
|
<!-- Bluetooth errored subtext - shown when Bluetooth is broken for some reason [CHAR LIMIT=50]-->
|
||||||
<string name="bluetooth_tethering_errored_subtext">Bluetooth tethering error</string>
|
<string name="bluetooth_tethering_errored_subtext">Bluetooth tethering error</string>
|
||||||
<!-- Bluetooth Tethering settings. Error message shown when trying to connect an 8th device [CHAR LIMIT=50]-->
|
<!-- Bluetooth Tethering settings. Error message shown when trying to connect an 8th device [CHAR LIMIT=50]-->
|
||||||
|
@@ -95,6 +95,8 @@ public class TetherSettings extends SettingsPreferenceFragment
|
|||||||
private WifiManager mWifiManager;
|
private WifiManager mWifiManager;
|
||||||
private WifiConfiguration mWifiConfig = null;
|
private WifiConfiguration mWifiConfig = null;
|
||||||
|
|
||||||
|
private boolean mBluetoothEnableForTether;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle icicle) {
|
public void onCreate(Bundle icicle) {
|
||||||
super.onCreate(icicle);
|
super.onCreate(icicle);
|
||||||
@@ -239,7 +241,8 @@ public class TetherSettings extends SettingsPreferenceFragment
|
|||||||
private class TetherChangeReceiver extends BroadcastReceiver {
|
private class TetherChangeReceiver extends BroadcastReceiver {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context content, Intent intent) {
|
public void onReceive(Context content, Intent intent) {
|
||||||
if (intent.getAction().equals(ConnectivityManager.ACTION_TETHER_STATE_CHANGED)) {
|
String action = intent.getAction();
|
||||||
|
if (action.equals(ConnectivityManager.ACTION_TETHER_STATE_CHANGED)) {
|
||||||
// TODO - this should understand the interface types
|
// TODO - this should understand the interface types
|
||||||
ArrayList<String> available = intent.getStringArrayListExtra(
|
ArrayList<String> available = intent.getStringArrayListExtra(
|
||||||
ConnectivityManager.EXTRA_AVAILABLE_TETHER);
|
ConnectivityManager.EXTRA_AVAILABLE_TETHER);
|
||||||
@@ -250,10 +253,27 @@ public class TetherSettings extends SettingsPreferenceFragment
|
|||||||
updateState(available.toArray(new String[available.size()]),
|
updateState(available.toArray(new String[available.size()]),
|
||||||
active.toArray(new String[active.size()]),
|
active.toArray(new String[active.size()]),
|
||||||
errored.toArray(new String[errored.size()]));
|
errored.toArray(new String[errored.size()]));
|
||||||
} else if (intent.getAction().equals(Intent.ACTION_MEDIA_SHARED) ||
|
} else if (action.equals(Intent.ACTION_MEDIA_SHARED) ||
|
||||||
intent.getAction().equals(Intent.ACTION_MEDIA_UNSHARED)) {
|
action.equals(Intent.ACTION_MEDIA_UNSHARED)) {
|
||||||
updateState();
|
updateState();
|
||||||
} else if (intent.getAction().equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
|
} else if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
|
||||||
|
if (mBluetoothEnableForTether) {
|
||||||
|
switch (intent
|
||||||
|
.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR)) {
|
||||||
|
case BluetoothAdapter.STATE_ON:
|
||||||
|
mBluetoothPan.setBluetoothTethering(true);
|
||||||
|
mBluetoothEnableForTether = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BluetoothAdapter.STATE_OFF:
|
||||||
|
case BluetoothAdapter.ERROR:
|
||||||
|
mBluetoothEnableForTether = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// ignore transition states
|
||||||
|
}
|
||||||
|
}
|
||||||
updateState();
|
updateState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -281,6 +301,8 @@ public class TetherSettings extends SettingsPreferenceFragment
|
|||||||
|
|
||||||
if (intent != null) mTetherChangeReceiver.onReceive(activity, intent);
|
if (intent != null) mTetherChangeReceiver.onReceive(activity, intent);
|
||||||
mWifiApEnabler.resume();
|
mWifiApEnabler.resume();
|
||||||
|
|
||||||
|
updateState();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -368,22 +390,10 @@ public class TetherSettings extends SettingsPreferenceFragment
|
|||||||
|
|
||||||
private void updateBluetoothState(String[] available, String[] tethered,
|
private void updateBluetoothState(String[] available, String[] tethered,
|
||||||
String[] errored) {
|
String[] errored) {
|
||||||
ConnectivityManager cm =
|
int bluetoothTethered = 0;
|
||||||
(ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
|
|
||||||
int bluetoothError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
|
|
||||||
for (String s : available) {
|
|
||||||
for (String regex : mBluetoothRegexs) {
|
|
||||||
if (s.matches(regex)) {
|
|
||||||
if (bluetoothError == ConnectivityManager.TETHER_ERROR_NO_ERROR) {
|
|
||||||
bluetoothError = cm.getLastTetherError(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
boolean bluetoothTethered = false;
|
|
||||||
for (String s : tethered) {
|
for (String s : tethered) {
|
||||||
for (String regex : mBluetoothRegexs) {
|
for (String regex : mBluetoothRegexs) {
|
||||||
if (s.matches(regex)) bluetoothTethered = true;
|
if (s.matches(regex)) bluetoothTethered++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
boolean bluetoothErrored = false;
|
boolean bluetoothErrored = false;
|
||||||
@@ -401,18 +411,20 @@ public class TetherSettings extends SettingsPreferenceFragment
|
|||||||
} else if (btState == BluetoothAdapter.STATE_TURNING_ON) {
|
} else if (btState == BluetoothAdapter.STATE_TURNING_ON) {
|
||||||
mBluetoothTether.setEnabled(false);
|
mBluetoothTether.setEnabled(false);
|
||||||
mBluetoothTether.setSummary(R.string.bluetooth_turning_on);
|
mBluetoothTether.setSummary(R.string.bluetooth_turning_on);
|
||||||
} else if (mBluetoothPan.isTetheringOn()) {
|
} else if (btState == BluetoothAdapter.STATE_ON && mBluetoothPan.isTetheringOn()) {
|
||||||
mBluetoothTether.setChecked(true);
|
mBluetoothTether.setChecked(true);
|
||||||
if (btState == BluetoothAdapter.STATE_ON) {
|
|
||||||
mBluetoothTether.setEnabled(true);
|
mBluetoothTether.setEnabled(true);
|
||||||
if (bluetoothTethered) {
|
if (bluetoothTethered > 1) {
|
||||||
mBluetoothTether.setSummary(R.string.bluetooth_tethering_connected_subtext);
|
String summary = getString(
|
||||||
|
R.string.bluetooth_tethering_devices_connected_subtext, bluetoothTethered);
|
||||||
|
mBluetoothTether.setSummary(summary);
|
||||||
|
} else if (bluetoothTethered == 1) {
|
||||||
|
mBluetoothTether.setSummary(R.string.bluetooth_tethering_device_connected_subtext);
|
||||||
} else if (bluetoothErrored) {
|
} else if (bluetoothErrored) {
|
||||||
mBluetoothTether.setSummary(R.string.bluetooth_tethering_errored_subtext);
|
mBluetoothTether.setSummary(R.string.bluetooth_tethering_errored_subtext);
|
||||||
} else {
|
} else {
|
||||||
mBluetoothTether.setSummary(R.string.bluetooth_tethering_available_subtext);
|
mBluetoothTether.setSummary(R.string.bluetooth_tethering_available_subtext);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
mBluetoothTether.setEnabled(true);
|
mBluetoothTether.setEnabled(true);
|
||||||
mBluetoothTether.setChecked(false);
|
mBluetoothTether.setChecked(false);
|
||||||
@@ -456,20 +468,21 @@ public class TetherSettings extends SettingsPreferenceFragment
|
|||||||
}
|
}
|
||||||
mUsbTether.setSummary("");
|
mUsbTether.setSummary("");
|
||||||
}
|
}
|
||||||
} else if(preference == mBluetoothTether) {
|
} else if (preference == mBluetoothTether) {
|
||||||
boolean bluetoothTetherState = mBluetoothTether.isChecked();
|
boolean bluetoothTetherState = mBluetoothTether.isChecked();
|
||||||
|
|
||||||
if (bluetoothTetherState) {
|
if (bluetoothTetherState) {
|
||||||
// turn on Bluetooth first
|
// turn on Bluetooth first
|
||||||
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
|
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
|
||||||
if (adapter.getState() == BluetoothAdapter.STATE_OFF) {
|
if (adapter.getState() == BluetoothAdapter.STATE_OFF) {
|
||||||
|
mBluetoothEnableForTether = true;
|
||||||
adapter.enable();
|
adapter.enable();
|
||||||
mBluetoothTether.setSummary(R.string.bluetooth_turning_on);
|
mBluetoothTether.setSummary(R.string.bluetooth_turning_on);
|
||||||
mBluetoothTether.setEnabled(false);
|
mBluetoothTether.setEnabled(false);
|
||||||
}
|
} else {
|
||||||
|
|
||||||
mBluetoothPan.setBluetoothTethering(true);
|
mBluetoothPan.setBluetoothTethering(true);
|
||||||
mBluetoothTether.setSummary(R.string.bluetooth_tethering_available_subtext);
|
mBluetoothTether.setSummary(R.string.bluetooth_tethering_available_subtext);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
boolean errored = false;
|
boolean errored = false;
|
||||||
|
|
||||||
|
@@ -142,7 +142,7 @@ final class A2dpProfile implements LocalBluetoothProfile {
|
|||||||
return R.string.bluetooth_profile_a2dp;
|
return R.string.bluetooth_profile_a2dp;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getDisconnectResource() {
|
public int getDisconnectResource(BluetoothDevice device) {
|
||||||
return R.string.bluetooth_disconnect_a2dp_profile;
|
return R.string.bluetooth_disconnect_a2dp_profile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -51,6 +51,13 @@ final class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> {
|
|||||||
private final List<LocalBluetoothProfile> mProfiles =
|
private final List<LocalBluetoothProfile> mProfiles =
|
||||||
new ArrayList<LocalBluetoothProfile>();
|
new ArrayList<LocalBluetoothProfile>();
|
||||||
|
|
||||||
|
// List of profiles that were previously in mProfiles, but have been removed
|
||||||
|
private final List<LocalBluetoothProfile> mRemovedProfiles =
|
||||||
|
new ArrayList<LocalBluetoothProfile>();
|
||||||
|
|
||||||
|
// Device supports PANU but not NAP: remove PanProfile after device disconnects from NAP
|
||||||
|
private boolean mLocalNapRoleConnected;
|
||||||
|
|
||||||
private boolean mVisible;
|
private boolean mVisible;
|
||||||
|
|
||||||
private final Collection<Callback> mCallbacks = new ArrayList<Callback>();
|
private final Collection<Callback> mCallbacks = new ArrayList<Callback>();
|
||||||
@@ -100,9 +107,22 @@ final class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> {
|
|||||||
mProfileConnectionState.put(profile, newProfileState);
|
mProfileConnectionState.put(profile, newProfileState);
|
||||||
if (newProfileState == BluetoothProfile.STATE_CONNECTED) {
|
if (newProfileState == BluetoothProfile.STATE_CONNECTED) {
|
||||||
if (!mProfiles.contains(profile)) {
|
if (!mProfiles.contains(profile)) {
|
||||||
|
mRemovedProfiles.remove(profile);
|
||||||
mProfiles.add(profile);
|
mProfiles.add(profile);
|
||||||
|
if (profile instanceof PanProfile &&
|
||||||
|
((PanProfile) profile).isLocalRoleNap(mDevice)) {
|
||||||
|
// Device doesn't support NAP, so remove PanProfile on disconnect
|
||||||
|
mLocalNapRoleConnected = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (mLocalNapRoleConnected && profile instanceof PanProfile &&
|
||||||
|
((PanProfile) profile).isLocalRoleNap(mDevice) &&
|
||||||
|
newProfileState == BluetoothProfile.STATE_DISCONNECTED) {
|
||||||
|
Log.d(TAG, "Removing PanProfile from device after NAP disconnect");
|
||||||
|
mProfiles.remove(profile);
|
||||||
|
mRemovedProfiles.add(profile);
|
||||||
|
mLocalNapRoleConnected = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CachedBluetoothDevice(LocalBluetoothAdapter adapter,
|
CachedBluetoothDevice(LocalBluetoothAdapter adapter,
|
||||||
@@ -391,7 +411,7 @@ final class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> {
|
|||||||
ParcelUuid[] localUuids = mLocalAdapter.getUuids();
|
ParcelUuid[] localUuids = mLocalAdapter.getUuids();
|
||||||
if (localUuids == null) return false;
|
if (localUuids == null) return false;
|
||||||
|
|
||||||
mProfileManager.updateProfiles(uuids, localUuids, mProfiles);
|
mProfileManager.updateProfiles(uuids, localUuids, mProfiles, mRemovedProfiles);
|
||||||
|
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.e(TAG, "updating profiles for " + mDevice.getName());
|
Log.e(TAG, "updating profiles for " + mDevice.getName());
|
||||||
@@ -482,6 +502,10 @@ final class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> {
|
|||||||
return connectableProfiles;
|
return connectableProfiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<LocalBluetoothProfile> getRemovedProfiles() {
|
||||||
|
return mRemovedProfiles;
|
||||||
|
}
|
||||||
|
|
||||||
void registerCallback(Callback callback) {
|
void registerCallback(Callback callback) {
|
||||||
synchronized (mCallbacks) {
|
synchronized (mCallbacks) {
|
||||||
mCallbacks.add(callback);
|
mCallbacks.add(callback);
|
||||||
|
@@ -239,7 +239,7 @@ public final class DeviceProfilesSettings extends SettingsPreferenceFragment
|
|||||||
if (TextUtils.isEmpty(name)) {
|
if (TextUtils.isEmpty(name)) {
|
||||||
name = context.getString(R.string.bluetooth_device);
|
name = context.getString(R.string.bluetooth_device);
|
||||||
}
|
}
|
||||||
int disconnectMessage = profile.getDisconnectResource();
|
int disconnectMessage = profile.getDisconnectResource(device.getDevice());
|
||||||
if (disconnectMessage == 0) {
|
if (disconnectMessage == 0) {
|
||||||
Log.w(TAG, "askDisconnect: unexpected profile " + profile);
|
Log.w(TAG, "askDisconnect: unexpected profile " + profile);
|
||||||
disconnectMessage = R.string.bluetooth_disconnect_blank;
|
disconnectMessage = R.string.bluetooth_disconnect_blank;
|
||||||
@@ -288,6 +288,13 @@ public final class DeviceProfilesSettings extends SettingsPreferenceFragment
|
|||||||
refreshProfilePreference(profilePref, profile);
|
refreshProfilePreference(profilePref, profile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (LocalBluetoothProfile profile : mCachedDevice.getRemovedProfiles()) {
|
||||||
|
Preference profilePref = findPreference(profile.toString());
|
||||||
|
if (profilePref != null) {
|
||||||
|
Log.d(TAG, "Removing " + profile.toString() + " from profile list");
|
||||||
|
mProfileContainer.removePreference(profilePref);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void refreshProfilePreference(Preference profilePref, LocalBluetoothProfile profile) {
|
private void refreshProfilePreference(Preference profilePref, LocalBluetoothProfile profile) {
|
||||||
|
@@ -22,13 +22,11 @@ import android.bluetooth.BluetoothHeadset;
|
|||||||
import android.bluetooth.BluetoothProfile;
|
import android.bluetooth.BluetoothProfile;
|
||||||
import android.bluetooth.BluetoothUuid;
|
import android.bluetooth.BluetoothUuid;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Handler;
|
|
||||||
import android.os.ParcelUuid;
|
import android.os.ParcelUuid;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -176,7 +174,7 @@ final class HeadsetProfile implements LocalBluetoothProfile {
|
|||||||
return R.string.bluetooth_profile_headset;
|
return R.string.bluetooth_profile_headset;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getDisconnectResource() {
|
public int getDisconnectResource(BluetoothDevice device) {
|
||||||
return R.string.bluetooth_disconnect_headset_profile;
|
return R.string.bluetooth_disconnect_headset_profile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -116,7 +116,7 @@ final class HidProfile implements LocalBluetoothProfile {
|
|||||||
return R.string.bluetooth_profile_hid;
|
return R.string.bluetooth_profile_hid;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getDisconnectResource() {
|
public int getDisconnectResource(BluetoothDevice device) {
|
||||||
return R.string.bluetooth_disconnect_hid_profile;
|
return R.string.bluetooth_disconnect_hid_profile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -60,8 +60,9 @@ interface LocalBluetoothProfile {
|
|||||||
/**
|
/**
|
||||||
* Returns the string resource ID for the disconnect confirmation text
|
* Returns the string resource ID for the disconnect confirmation text
|
||||||
* for this profile.
|
* for this profile.
|
||||||
|
* @param device
|
||||||
*/
|
*/
|
||||||
int getDisconnectResource();
|
int getDisconnectResource(BluetoothDevice device);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the string resource ID for the summary text for this profile
|
* Returns the string resource ID for the summary text for this profile
|
||||||
|
@@ -110,7 +110,9 @@ final class LocalBluetoothProfileManager {
|
|||||||
BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED);
|
BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED);
|
||||||
|
|
||||||
mPanProfile = new PanProfile(context);
|
mPanProfile = new PanProfile(context);
|
||||||
addProfile(mPanProfile, PanProfile.NAME, BluetoothPan.ACTION_CONNECTION_STATE_CHANGED);
|
addPanProfile(mPanProfile, PanProfile.NAME,
|
||||||
|
BluetoothPan.ACTION_CONNECTION_STATE_CHANGED);
|
||||||
|
|
||||||
Log.d(TAG, "LocalBluetoothProfileManager construction complete");
|
Log.d(TAG, "LocalBluetoothProfileManager construction complete");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,6 +175,13 @@ final class LocalBluetoothProfileManager {
|
|||||||
mProfileNameMap.put(profileName, profile);
|
mProfileNameMap.put(profileName, profile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addPanProfile(LocalBluetoothProfile profile,
|
||||||
|
String profileName, String stateChangedAction) {
|
||||||
|
mEventManager.addProfileHandler(stateChangedAction,
|
||||||
|
new PanStateChangedHandler(profile));
|
||||||
|
mProfileNameMap.put(profileName, profile);
|
||||||
|
}
|
||||||
|
|
||||||
LocalBluetoothProfile getProfileByName(String name) {
|
LocalBluetoothProfile getProfileByName(String name) {
|
||||||
return mProfileNameMap.get(name);
|
return mProfileNameMap.get(name);
|
||||||
}
|
}
|
||||||
@@ -190,7 +199,7 @@ final class LocalBluetoothProfileManager {
|
|||||||
* Generic handler for connection state change events for the specified profile.
|
* Generic handler for connection state change events for the specified profile.
|
||||||
*/
|
*/
|
||||||
private class StateChangedHandler implements BluetoothEventManager.Handler {
|
private class StateChangedHandler implements BluetoothEventManager.Handler {
|
||||||
private final LocalBluetoothProfile mProfile;
|
final LocalBluetoothProfile mProfile;
|
||||||
|
|
||||||
StateChangedHandler(LocalBluetoothProfile profile) {
|
StateChangedHandler(LocalBluetoothProfile profile) {
|
||||||
mProfile = profile;
|
mProfile = profile;
|
||||||
@@ -215,6 +224,22 @@ final class LocalBluetoothProfileManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** State change handler for NAP and PANU profiles. */
|
||||||
|
private class PanStateChangedHandler extends StateChangedHandler {
|
||||||
|
|
||||||
|
PanStateChangedHandler(LocalBluetoothProfile profile) {
|
||||||
|
super(profile);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent, BluetoothDevice device) {
|
||||||
|
PanProfile panProfile = (PanProfile) mProfile;
|
||||||
|
int role = intent.getIntExtra(BluetoothPan.EXTRA_LOCAL_ROLE, 0);
|
||||||
|
panProfile.setLocalRole(device, role);
|
||||||
|
super.onReceive(context, intent, device);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// called from DockService
|
// called from DockService
|
||||||
void addServiceListener(ServiceListener l) {
|
void addServiceListener(ServiceListener l) {
|
||||||
mServiceListeners.add(l);
|
mServiceListeners.add(l);
|
||||||
@@ -269,9 +294,14 @@ final class LocalBluetoothProfileManager {
|
|||||||
* @param uuids of the remote device
|
* @param uuids of the remote device
|
||||||
* @param localUuids UUIDs of the local device
|
* @param localUuids UUIDs of the local device
|
||||||
* @param profiles The list of profiles to fill
|
* @param profiles The list of profiles to fill
|
||||||
|
* @param removedProfiles list of profiles that were removed
|
||||||
*/
|
*/
|
||||||
synchronized void updateProfiles(ParcelUuid[] uuids, ParcelUuid[] localUuids,
|
synchronized void updateProfiles(ParcelUuid[] uuids, ParcelUuid[] localUuids,
|
||||||
Collection<LocalBluetoothProfile> profiles) {
|
Collection<LocalBluetoothProfile> profiles,
|
||||||
|
Collection<LocalBluetoothProfile> removedProfiles) {
|
||||||
|
// Copy previous profile list into removedProfiles
|
||||||
|
removedProfiles.clear();
|
||||||
|
removedProfiles.addAll(profiles);
|
||||||
profiles.clear();
|
profiles.clear();
|
||||||
|
|
||||||
if (uuids == null) {
|
if (uuids == null) {
|
||||||
@@ -284,27 +314,32 @@ final class LocalBluetoothProfileManager {
|
|||||||
(BluetoothUuid.isUuidPresent(localUuids, BluetoothUuid.Handsfree_AG) &&
|
(BluetoothUuid.isUuidPresent(localUuids, BluetoothUuid.Handsfree_AG) &&
|
||||||
BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Handsfree))) {
|
BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Handsfree))) {
|
||||||
profiles.add(mHeadsetProfile);
|
profiles.add(mHeadsetProfile);
|
||||||
|
removedProfiles.remove(mHeadsetProfile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (BluetoothUuid.containsAnyUuid(uuids, A2dpProfile.SINK_UUIDS) &&
|
if (BluetoothUuid.containsAnyUuid(uuids, A2dpProfile.SINK_UUIDS) &&
|
||||||
mA2dpProfile != null) {
|
mA2dpProfile != null) {
|
||||||
profiles.add(mA2dpProfile);
|
profiles.add(mA2dpProfile);
|
||||||
|
removedProfiles.remove(mA2dpProfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.ObexObjectPush) &&
|
if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.ObexObjectPush) &&
|
||||||
mOppProfile != null) {
|
mOppProfile != null) {
|
||||||
profiles.add(mOppProfile);
|
profiles.add(mOppProfile);
|
||||||
|
removedProfiles.remove(mOppProfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Hid) &&
|
if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Hid) &&
|
||||||
mHidProfile != null) {
|
mHidProfile != null) {
|
||||||
profiles.add(mHidProfile);
|
profiles.add(mHidProfile);
|
||||||
|
removedProfiles.remove(mHidProfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.NAP) &&
|
if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.NAP) &&
|
||||||
mPanProfile != null) {
|
mPanProfile != null) {
|
||||||
profiles.add(mPanProfile);
|
profiles.add(mPanProfile);
|
||||||
|
removedProfiles.remove(mPanProfile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -79,7 +79,7 @@ final class OppProfile implements LocalBluetoothProfile {
|
|||||||
return R.string.bluetooth_profile_opp;
|
return R.string.bluetooth_profile_opp;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getDisconnectResource() {
|
public int getDisconnectResource(BluetoothDevice device) {
|
||||||
return 0; // user must use notification to disconnect OPP transfer.
|
return 0; // user must use notification to disconnect OPP transfer.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -25,14 +25,19 @@ import android.content.Context;
|
|||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PanProfile handles Bluetooth PAN profile.
|
* PanProfile handles Bluetooth PAN profile (NAP and PANU).
|
||||||
*/
|
*/
|
||||||
final class PanProfile implements LocalBluetoothProfile {
|
final class PanProfile implements LocalBluetoothProfile {
|
||||||
private BluetoothPan mService;
|
private BluetoothPan mService;
|
||||||
|
|
||||||
|
// Tethering direction for each device
|
||||||
|
private final HashMap<BluetoothDevice, Integer> mDeviceRoleMap =
|
||||||
|
new HashMap<BluetoothDevice, Integer>();
|
||||||
|
|
||||||
static final String NAME = "PAN";
|
static final String NAME = "PAN";
|
||||||
|
|
||||||
// Order of this profile in device profiles list
|
// Order of this profile in device profiles list
|
||||||
@@ -111,8 +116,12 @@ final class PanProfile implements LocalBluetoothProfile {
|
|||||||
return R.string.bluetooth_profile_pan;
|
return R.string.bluetooth_profile_pan;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getDisconnectResource() {
|
public int getDisconnectResource(BluetoothDevice device) {
|
||||||
return R.string.bluetooth_disconnect_pan_profile;
|
if (isLocalRoleNap(device)) {
|
||||||
|
return R.string.bluetooth_disconnect_pan_nap_profile;
|
||||||
|
} else {
|
||||||
|
return R.string.bluetooth_disconnect_pan_user_profile;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSummaryResourceForDevice(BluetoothDevice device) {
|
public int getSummaryResourceForDevice(BluetoothDevice device) {
|
||||||
@@ -122,7 +131,11 @@ final class PanProfile implements LocalBluetoothProfile {
|
|||||||
return R.string.bluetooth_pan_profile_summary_use_for;
|
return R.string.bluetooth_pan_profile_summary_use_for;
|
||||||
|
|
||||||
case BluetoothProfile.STATE_CONNECTED:
|
case BluetoothProfile.STATE_CONNECTED:
|
||||||
return R.string.bluetooth_pan_profile_summary_connected;
|
if (isLocalRoleNap(device)) {
|
||||||
|
return R.string.bluetooth_pan_nap_profile_summary_connected;
|
||||||
|
} else {
|
||||||
|
return R.string.bluetooth_pan_user_profile_summary_connected;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return Utils.getConnectionStateSummary(state);
|
return Utils.getConnectionStateSummary(state);
|
||||||
@@ -132,4 +145,17 @@ final class PanProfile implements LocalBluetoothProfile {
|
|||||||
public int getDrawableResource(BluetoothClass btClass) {
|
public int getDrawableResource(BluetoothClass btClass) {
|
||||||
return R.drawable.ic_bt_network_pan;
|
return R.drawable.ic_bt_network_pan;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tethering direction determines UI strings.
|
||||||
|
void setLocalRole(BluetoothDevice device, int role) {
|
||||||
|
mDeviceRoleMap.put(device, role);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isLocalRoleNap(BluetoothDevice device) {
|
||||||
|
if (mDeviceRoleMap.containsKey(device)) {
|
||||||
|
return mDeviceRoleMap.get(device) == BluetoothPan.LOCAL_NAP_ROLE;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user